【剑指offer】第五十七题(和为 s 的两个数字) 和 第五十八题(翻转字符串)

第五十七题:和为 s 的两个数字

题目:

输入一个递增的排序数组和一个数字 s ,在数组中查找两个数,使得它们的和正好是 s 。如果有多对数字的和等于 s ,则输出任意一对即可。

解题程序:

#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std;

// 算法思想:
//          1.设置两个指针,第一个指针指向排序数组的首元素,第二个指针指向数组元素的最后一个元素的位置
//          2.求两个指针所指元素的和,如果两个元素的和大于输入的数字,则尾指针向前移动一位;如果和小于输入数字,
//              则指向首元素的指针向后移动一位;如果和刚好等于输入的数字,那么这两个指针所指元素就是要查找的 数字

bool FindNumbersWithSum(int data[],int len,int sum,int *num1,int *num2)
{
    bool found = false;
    
    if( data == NULL|| len<1 || num1 == NULL || num2 == NULL )
        return found;
    int ahead = len - 1;
    int behind = 0;
    
    while(behind < ahead)
    {
       long long CurSum = data[ahead]  + data[behind];
        
        if(CurSum == sum)
        {
            *num1 = data[behind];
            *num2 = data[ahead];
            found = true;
            break;
        }
        else if(CurSum > sum)
            ahead--;
        else
            behind++;

    }

    return found;
}

// 测试用例

void test()
{
    int data[100] = {0};
    int i = 0;
    int value;
    printf("输入排序数组,以 -1 结束:\n");
    scanf("%d",&value);

    while(value != -1)
    {
        data[i++] = value;
        scanf("%d",&value);
    }
    int len = i; 

    int sum = 0;
    printf("输入要查找的数字的和:\n");
    scanf("%d",&sum);

    int num1;
    int num2;
    bool ret = FindNumbersWithSum(data,len,sum,&num1,&num2);
    if(ret)
        printf("%d = %d + %d\n",sum,num1,num2);
    else
        printf("在排序数组中没有找到两个数的和为 %d\n",sum);
}

int main(void)
{
    test();
    return 0;
}


测试用例:


题目二:和为 s 的连续正数序列

输入一个正数 s ,打印出所有和 为 s 的连续正数序列(至少含有两个数)。例如,输入 15,由于 1+2+3+4+5 = 4+5+6 = 15。所以打印出 3 个连续序列 1 ~ 5、4 ~ 6 和 7 ~ 8。


解题程序:

#include<iostream>
#include<stdio.h>
using namespace std;

// 算法思想:
//          1.设置连个变量,small = 1,big = 2;
//          2.如果从 small 到 big 的序列数字之和大于 s ,则可以去掉序列中较小的值;如果序列之和小于 s,则增大 big,知道增到到
//              small  到 (1+s)/2 为止;如果序列之和等于 s ,则打印出各个和为 s 的序列

// 打印和为 s 的序列

void PrintContinuosSequence(int small,int big)
{
    for(int i=small;i<=big;i++)
    {
        printf("%d\t",i);
    }
    
    printf("\n");
}


void FindContinuousSequence(int sum)
{
    // 判断边界条件
   if(sum<3) 
        return;
   
    int small = 1;
    int big = 2;
    int end = (1+sum) / 2;
    int CurSum = small + big;
   
    // 要保证序列中的最小值小于 (1+s)/2 的值
    while(small < end)
    {
        if(CurSum == sum) 
            PrintContinuosSequence(small,big);

        // 如果序列之和不等于 s,并且当前序列之和大于 s
        while(CurSum > sum && small < end)
        {
            // 去掉最小的数值
            CurSum -= small;
            small++;

            if( CurSum == sum )
                PrintContinuosSequence(small,big);
        }
        
        // 如果序列之和小于 s
        // 序列继续向后移动
        big++;
        CurSum += big;
    }

}


// 测试用例:

void test()
{
    int s;
    printf("请输入序列的和:\n");
    scanf("%d",&s);
   
    // 获取和 s 的子序列
    FindContinuousSequence(s);
}

int main(void)
{
    test();
    return 0;
}

测试用例:



第五十八题:翻转字符串

题目:翻转单词顺序

   输入一个英文句子,翻转句子中单词的顺序,但单词内的字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串 “I am a student.”,则输出 “stundet. a am I ”。


解题程序:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

// 算法思想:
//          1、先给 整个字符串逆序
//          2、然后给每个单词包括标点符号逆序,即可得到结果


void  Reverse(char *pBegin,char* pEnd)
{
   if(pBegin == NULL || pEnd == NULL) 
        return;
   
    // 字符串逆序
    while(pBegin < pEnd)
    {
       char temp = *pBegin; 
        *pBegin = *pEnd;
        *pEnd = temp;
    
        pBegin++;
        pEnd--;
    }
}

char *ReverseSentence(char *pData)
{
    printf("pData = %s\n",pData);
   if(pData == NULL) 
        return NULL;

    // 指向字符串的首元素
    char *pBegin = pData;
    // 指向字符串的尾部元素
    char *pEnd = pData;
    
    while(*pEnd != '\0')
        pEnd++;

    pEnd--;


    // 先翻转整个句子,即逆序整个句子
    Reverse(pBegin,pEnd);

    // 翻转句子中的每个单词以及标点符号

    pBegin = pEnd = pData;

    // 循环遍历字符串中的单词,并翻转
    while(*pBegin != '\0')
    {
        // 如果是空格的话,指向单词首元素的 指针和尾指针都向后移动一个字符,跳过空格
       if(*pBegin == ' ') 
        {
           pBegin++;
            pEnd++;
        }
        // 如果尾指针指向空格或者指向 '\0',则逆序单词
        else if(*pEnd == ' ' || *pEnd == '\0')
        {
           Reverse(pBegin,--pEnd); 

            // 尾指针向后移动一个字符,继续遍历
            pEnd++;
            // 头指针指向下一个单词的第一个字符
            pBegin = pEnd;
        }
        else
            pEnd++;

    }
    printf("pData = %s\n",pData);
    return pData;
}

// 测试用例

void test()
{
    char str[] = "I am a student.";
    char *pStr = NULL; 
    pStr = ReverseSentence(str);
    if( pStr != NULL )
        printf("逆序后的结果为:%s\n",pStr);
    else
       printf("程序出错!\n"); 

    char *str1 = NULL;
    pStr = ReverseSentence(str1);
    if( pStr != NULL )
        printf("逆序后的结果为:%s\n",pStr);
    else
        printf("程序出错!\n"); 
    
    char str2[] = "beautiful";
    pStr = ReverseSentence(str2);
    if( pStr != NULL )
        printf("逆序后的结果为:%s\n",pStr);
    else
       printf("程序出错!\n");     
}

int main(void)
{
    test();
    return 0;
}

测试用例:



题目二:左旋转字符串

字符串的左旋操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋操作的功能。比如,输入字符串 “abcdefg”和 数字 2,该函数将返回左旋转两位得到的结果,"cdefgab"。

解题程序:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

// 算法思想:
//          1.先把字符串的前 n 个字符翻转
//          2、然后把剩下的字符翻转
//          3、最后把整个字符串翻转

void Reverse(char *pBegin,char *pEnd)
{
    if(pBegin == NULL || pEnd == NULL)
        return;
    
    while(pBegin < pEnd)
    {
        char temp = *pBegin;        
        *pBegin = *pEnd;
        *pEnd = temp;

        pBegin++;
        pEnd--;
    }
}

char *LeftRotateString(char *pStr,int n)
{
   if(pStr != NULL) 
    {
        int nLength = strlen(pStr);
        if(nLength >0 && n>0 && n<nLength)
        {
            char *pFirstStart = pStr;
            char *pFirstEnd = pStr + n - 1;
            char *pSecondStart = pStr + n;
            char *pSecondEnd = pStr + nLength - 1;
            
            // 翻转字符串的前面 n 个字符
            Reverse(pFirstStart,pFirstEnd);
            
            // 翻转字符串的后面部分
            Reverse(pSecondStart,pSecondEnd);

            // 翻转整个字符串
            Reverse(pFirstStart,pSecondEnd);

        }
    }
    
    return pStr;
}

// 测试用例

void test()
{
    char str1[] = "abcdefg";
    int len = strlen(str1);
    char *pstr = NULL;

    pstr = LeftRotateString(str1,0);
    if( pstr == NULL )
        printf("error\n");
    else
        printf("字符串%s 从第 %d 个字符翻转后的结果为: %s\n",str1,0,pstr);

    // 左旋 1 个字符
    
    char str2[] = "abcdefg";
    pstr = LeftRotateString(str2,1);
    if( pstr == NULL )
        printf("error\n");
    else
        printf("字符串%s 从第 %d 个字符翻转后的结果为: %s\n",str2,1,pstr);

    // 左旋 2 个字符
    char str3[] = "abcdefg";
    pstr = LeftRotateString(str3,2);
    if( pstr == NULL )
        printf("error\n");
    else
        printf("字符串%s 从第 %d 个字符翻转后的结果为: %s\n",str3,2,pstr);

    // 左旋 len-1 个字符
    char str4[] = "abcdefg";
    pstr = LeftRotateString(str4,len-1);
    if( pstr == NULL )
        printf("error\n");
    else
        printf("字符串%s 从第 %d 个字符翻转后的结果为: %s\n",str4,len-1,pstr);
   
    // 左旋 len 个字符
    char str5[] = "abcdefg";
    pstr = LeftRotateString(str5,len);
    if( pstr == NULL )
        printf("error\n");
    else
        printf("字符串%s 从第 %d 个字符翻转后的结果为: %s\n",str5,len,pstr);
    
    // 左旋 len+1 个字符
    char str6[] = "abcdefg";
    pstr = LeftRotateString(str6,len+1);
    if( pstr == NULL )
        printf("error\n");
    else
        printf("字符串%s 从第 %d 个字符翻转后的结果为: %s\n",str6,len+1,pstr);

    // 字符串为 NULL
    pstr = LeftRotateString(NULL,0);
    if( pstr == NULL )
        printf("error\n");
    else
        printf("字符串%s 从第 %d 个字符翻转后的结果为: %s\n",str1,0,pstr);

}

int main(void)
{
    test();
    return 0;
}

测试用例:



猜你喜欢

转载自blog.csdn.net/qq_35396127/article/details/79962108