【C】翻转单词-刷题

目录

前言

一、58剑指offer翻转单词顺序(传送门)

二、151翻转字符串里的单词(传送门)

总结


前言


一、58剑指offer翻转单词顺序(传送门)

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

示例 1:

输入: "the sky is blue"
输出: "blue is sky the"
示例 2:

输入: "  hello world!  "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。

 🔑思路:

  • 双指针,都从右往左遍历字符串数组
  • start指针先找第一个非空字符
  • end指针固定该非空字符后,就找到了单词最后一个字母,固定该位置不动
  • start指针继续往前移动到单词首字母之前一格
  • current指针找到start指针后面一格
  • current指针到end指针区间即字母
  • index指针是新数组ans里的指针,从0开始向后移动
  • 每次加入单词后跳出循环后,加入一个空格' '
  • 在返回字符串数组末尾去掉空格并加上'\0'

        

char* reverseWords(char* s){
    int len = strlen(s);
    int left = len-1;   // 从右向左开始遍历
    int right = len-1;  // 从右向左开始遍历
    int tmp = 0;        // 目前指针的位置
    int index = 0;      // 索引记录
    char* ret = (char*)malloc(sizeof(char)*(len+1));        //1
    while(left>=0){
        if(s[left] == ' '){
            left--;                                         // 2
        }
        else{                                               // 3
            right = left;                                   // 4
            while(left >= 0 && s[left] != ' '){
                left--;                                     // 5
            }
            tmp = left+1;                                   // 6
            while(tmp <= right){                            // 7
                ret[index++] = s[tmp++];                    // 8
            }
                                                            // 9
            ret[index++] = ' ';                             // 10
        }
    }
    if(index>=1){                                           // 11
        ret[index-1]='\0';                                  // 12
    }
    else{
        ret = "";
    }
    return ret;
}
  1.  开辟空间多开一个
  2. 从右向左遍历,遇到空格指针就继续往左移动一格

  3. 从右向左遍历,遇到非空

  4. right指针赶紧来固定pin单词末尾的非空字母

  5. left指针继续往前移动到该单词第一个字母之前一格(空格)

  6. tmp指针移动到该单词的第一个字母

  7. 开始遍历这个单词

  8. 把tmp到right俩指针区间(含)之间指向的单词从前往后拷贝到新数组ret中            index为数组ret的指针,从0开始往后移动

      对于a[i++]和a[++i]:                                                                                                      i++是先使用i现在的值,再给i加1                                                                                 ++i是先给i加1,再用加1后的值

  9. ret[index + 1]出现blueisskyth(?)

  10. 每个单词加入后再加一个空格' ',然后index指针移动到下一位

  11. 不考虑'\0'就会出现“执行出错”:                                                                                      在字符串数组的末尾加上'\0'表示字符串结束. 如果没有这个\0,那么在使用系统函数处理这个字符串的时候,函数就不能准确判断字符串在哪里结束.从而导致数组越界                                                                                                                                                      替换最后的' '为'\0'                                                                                                          这句话在剑指offer58里没:由于s中至少存在一个单词!!!所以index要判断是否大于0                                                                                                                                    否则测试案例""无法通过(输入"",输出也应该为"",所以根本没进入while循环!!!)

  12. 不是index,是index-1,回退到index上一位

二、151翻转字符串里的单词(传送门)

给你一个字符串 s ,逐个翻转字符串中的所有 单词 。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。

说明:

输入字符串 s 可以在前面、后面或者单词间包含多余的空格。
翻转后单词间应当仅用一个空格分隔。
翻转后的字符串中不应包含额外的空格。
 

示例 1:

输入:s = "the sky is blue"
输出:"blue is sky the"
示例 2:

输入:s = "  hello world  "
输出:"world hello"
解释:输入字符串可以在前面或者后面包含多余的空格,但是翻转后的字符不能包括。

🔑思路:

  • 双指针,都从右往左遍历字符串数组
  • start指针先找第一个非空字符
  • end指针固定该非空字符后,就找到了单词最后一个字母,固定该位置不动
  • start指针继续往前移动到单词首字母之前一格
  • current指针找到start指针后面一格
  • current指针到end指针区间即字母
  • index指针是新数组ans里的指针,从0开始向后移动
  • 每次加入单词后跳出循环后,加入一个空格' '
  • 在返回字符串数组末尾去掉空格并加上'\0'
char *reverseWords(char *s)
{
    int len = strlen(s);
    char *ans = (char *)malloc(sizeof(char) * (len + 1));
    int start = len - 1; // 从右向左开始遍历
    int end = len - 1;   // 从右向左开始遍历
    int current = 0;     // 目前指针的位置
    int index = 0;       // 索引记录
    // start指针从右向左遍历,最左边为0,最右边为len - 1
    while (start >= 0)
    {
        if (s[start] == ' ')
        {
            start--; // 从右向左遍历,遇到空格指针就继续往左移动一格
        }
        else // 从右向左遍历,遇到非空
        {
            end = start; // end指针赶紧来固定pin单词末尾的非空字母
            while (start >= 0 && s[start] != ' ')
            {
                start--; // start指针继续往前移动到该单词第一个字母之前一格(空格)
            }
            current = start + 1;   // current指针移动到该单词的第一个字母
            while (current <= end) // 开始遍历这个单词
            {
                /* 
                 * 把current到end俩指针区间(含)之间指向的单词从前往后拷贝到新数组ans中
                 * index为数组ans的指针,从0开始往后移动
                 */

                /*
                 * 对于a[i++]和a[++i]:
                 * i++是先使用i现在的值,再给i加1
                 * ++i是先给i加1,再用加1后的值
                 */
                ans[index++] = s[current++];
            }
            // ans[index + 1]出现blueisskyth(?)
            ans[index++] = ' '; // 每个单词加入后再加一个空格' ',然后index指针移动到下一位
        }
    }
   /*
    * 不考虑'\0'就会出现“执行出错”:
    * 在字符串数组的末尾加上'\0'表示字符串结束. 如果没有这个\0,那么在使用系统函数处理这个字符串的时候,函数就不能准确判断字符串在哪里结束.从而导致数组越界
    * 由于s中至少存在一个单词,所以index一定大于0
    */

    /*
     * 在ans[index++]中index已经赋值' '后又加了1,移动到下一位,等待被赋值
     * 替换掉最后的' '为'\0'
     */
    ans[index - 1] = '\0';  // 不是index,是index-1,回退到index上一位
    return ans;
}


总结

        两题差异:     

  • 58比第151题多了标点符号和普通字母一样处理,但标点符号不影响任何代码改变
  • 第151题题目中有这样一句话:s中至少存在一个单词,但是本题中没有,所以index要判断是否大于0,否则测试案例""无法通过(输入"",输出也应该为"",所以根本没进入while循环!)

        那么最后我们就不能像第151题那样写成:

ans[index - 1] = '\0'; 

         而是分支考虑index是否大于0

if (index >= 1)
    ans[index - 1] = '\0'; // 不是index,是index-1,回退到index上一位
else
    ans = "";

        由于第151题一定至少有一个单词,不可能有空字符串"",所以最后写成考虑分支index的代码第151题里也可以AC(空字符串不对其产生影响,其实只有一个分支起作用)


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

penguin_bark

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值