代码随想录算法训练营第八天 | 344.反转字符串、541. 反转字符串II、剑指Offer 05.替换空格、151.翻转字符串里的单词 、 剑指Offer58-II.左旋转字符串

day_08

传送门

344. 反转字符串

  • 前后双指针同时遍历,交换左右边的值,复杂度 O(n)
    • 交换方式一:申请一个空间的char 保存数据,进行交换
    • 交换方式二:两数异或操作,位运算实现
  • 库函数的时间复杂度也是 O(n)
  • 代码实现
    • C语言
    void reverseString(char* s, int sSize){
      int i = 0;
      int j = sSize - 1;
      while ( i < j)
      {
          s[i] ^= s[j];       //  异或运算进行交换
          s[j] ^= s[i];
          s[i] ^= s[j];
          i++;
          j--;
      }
    }
    
    • java
    class Solution {
      public void reverseString(char[] s) {
          int i = 0;
          int j = s.length - 1;
          while ( i < j)
          {
              s[i] ^= s[j];       //  异或运算进行交换
              s[j] ^= s[i];
              s[i] ^= s[j];
              i++;
              j--;
          }
      }
    }
    

541. 反转字符串 II

  • 是上一题的升级版,第一眼看过去有两个思路
  • 递归处理,每次处理 2k 个字符量,总是出错,呜呜呜
  • 循环处理,同上每次 2k 字符量处理,每次循环 +2k
  • 代码实现
char * reverseStr(char * s, int k){
    int size = strlen(s);                       //  先得到字符串的长度
    int start = 0;                              //  每一组要处理的数组的起始下标
    int end = 0;                                //  每一组要处理的数组的结束下标

    for (int i = 0; i < size; i += 2*k){        //  给数组切片
        i + k >= size? k : i;                   //  其实下标+k,用来判断当前数组的长度与 k 的关系

        if (i + k >= size){                     //  处理剩余数组长度<= k的数组
            reverse(s, i, size - 1);
            continue;
        }
        
        reverse(s, i, i + k - 1);               //  反之,都是只处理前 k 个字符
        
    }
    
}

//  交换数组值的函数。需要数组进行修改
void reverse(char* s, int start, int end){
    for (int i = start, j = end; i < j; i++, j--){
        char temp = s[i];
        s[i] = s[j];
        s[j] = temp;
    }
}

5. 替换空格

  • 库函数很容易实现,但是这个问题是实现这样的一个库函数,所以不用库函数

  • 思路

    • 数组的大小是否需要扩容?如何扩容?
      • C 里面直接申请一个指定大小的数组
      • java 同样里可以申请一个指定大小数组
      • java 里还可以用 stringBuilder,遍历原先的字符串,直接从左到右替换目标值
    • 扩容完毕后,如何处理呢?
      • 左到右赋值,相对简便不少
      • 右到左的双指针赋值,给数组额外申请一部分空间,推荐选这个
  • 代码实现

    • C语言 (为什么这题里,不能使用 while(*s) ? 用了会报错 heap-buffer-overflow? 为什么呀)
      • 原因:s++的时候,首地址指针已被改变,所以读取的时候才会出问题!!!C指针使用时要注意呀!
    //  替换空格
    char* replaceSpace(char* s){
    int count = 0;              //  记录空格的个数
    int strLen = strlen(s);             //  记录字符串长度
    
      for (int i = 0; i < strLen; i++){
          count += ( s[i] == ' ');
      }
    
      //  统计个数是为了扩容,C里的字符串需要手动添加 '\0' 不要忘 !
      int newArrLen = count * 2 + strLen;
      char* res = malloc(sizeof(char) * newArrLen + 1);
    
      //  开始双指针
      int left = strLen - 1;
      int right = newArrLen - 1;
      res[newArrLen] = '\0';
    
      while (left >= 0){          //  遍历原先的数组,给扩容后的数组赋值
          if (s[left] == ' '){
              res[right--] = '0';
              res[right--] = '2';
              res[right--] = '%';
              left--;
              continue;
          }
          res[right--] = s[left--];
      }
      
      return res;
    
    }
    

151. 翻转字符串里的单词

  • 思路:快慢指针处理

    • 先处理空格
      • 默认每遇到一个单词的时候,slow先赋值一个空格,再快指针赋值慢指针
    • 整体反转,依旧使用快慢指针处理
    • 单个单词反转,快慢指针处理
  • C语言代码实现

//  处理字符串反转
void reverse(char *s, int start, int end){
    int i = start;
    int j = end;
    for (  ; i < j ; i++ , j--){
        char temp;
        temp = s[i];
        s[i] = s[j];
        s[j] = temp;
    }
}

//  处理字符串中的多余空格,使用快慢指针处理
//  C语言字符串的结尾有一个'\0'就表示该字符串结束了
void dealSpace(char* s, int size){
    int slow = 0;
    int fast = 0;
    for ( ; fast < size; fast++){       //  快指针遍历,赋值需要的数值给慢指针
        if (s[fast] != ' '){               //  找到单词的第一个字母
            if (slow != 0){
                s[slow++] = ' ';        //  给每一个单词前面添加空格
            }
            while (s[fast] != ' ' && s[fast]!='\0'){     //  处理每一个单词,
                s[slow++] = s[fast++];
            }
            fast--;                     //  记得回退一步fast
        }
    }
    s[slow] = '\0';                     //  给字符串末尾添加 '\0'
}


//  开始反转单词,先处理空格,再反转所有的字符串,最后反转每个单词
char * reverseWords(char * s){
    int size = strlen(s);
    dealSpace(s, size);             //  处理完所有的空格了

    size = strlen(s);                    //  空格处理完后,字符串的长度会发生改变!
    reverse(s, 0, size - 1);            //  字符串整体反转

    int wordStart = 0;                  //  快慢指针反转单个单词
    int wordEnd = 0;
    //  <= 是为了让fast可以指到 '\0',然后对最后一个单词处理,如果是 < ,if走不进去,最后一个单词不会被处理
    for ( ; wordEnd <= size; wordEnd++){
        if (s[wordEnd] == ' ' || s[wordEnd] == '\0'){
            reverse(s, wordStart, wordEnd - 1);
            wordStart = wordEnd + 1 ;
        }
    }

    return s;
}


剑指Offer58-II.左旋转字符串

  • 思路 1 :直接申请新数组处理,两个指针一前一后读完字符串赋值给新数组

  • 思路 2 :不申请额外O(n) 的空间处理

    • 先看看矩阵里的转置是怎么回事
      • 矩阵的转置操作是将元素的位置进行颠倒 A = (AT)
      • 在字符串里我们也可以看作字符串是一个一维矩阵,无论是否转置,我们都是用一个指针遍历这个一维矩阵的
      • 同时这个矩阵还可以看作是好几个分块矩阵拼起来的结果
      • 即 [ M ] = [ A B C ] ====> M = abcdef, A = ab, B = cd, C = ef
      • (AB)T = BTAT
    • 目标:AB ======> BA
      • 过程如下
        • AB ===> ATBT ===> (ATBT)T ===> BA
        • 翻译过来就是:先反转前面的部分,再反转后面的部分,最后全部反转
  • C语言代码实现如下

//  AB => A^T B^T => (A^T B^T)^T => BA

//  处理字符串反转
void reverse(char *s, int start, int end){
    int i = start;
    int j = end;
    for (  ; i < j ; i++ , j--){
        char temp;
        temp = s[i];
        s[i] = s[j];
        s[j] = temp;
    }
}

char* reverseLeftWords(char* s, int n){
    reverse(s, 0 , n-1);
    reverse(s, n, strlen(s) - 1);
    reverse(s, 0 , strlen(s) - 1);

    return s;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值