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

77 阅读3分钟

344. 反转字符串

链接

题目链接

文章链接

第一想法

比较简单,可以用js自带的reverse方法,代码如下:

function reverseString(s: string[]): void {
  s.reverse()
};

同时还有另一种方法,双指针,思路是只需要把数组的第i个和倒数的第i个交换文章就可以了

function reverseString(s: string[]): void {
    let n=s.length-1
   for(let i=0;i<s.length;i++){
       if(i>=n-i) return 
       let str=s[i]
       s[i]=s[n-i]
       s[n-i]=str
   }
};

看完文章后的想法

果然,文章也不让直接用方法解决,为了锻炼我们的思维逻辑。文章的整体和我的大差不差,唯一有一点我没见过的写法,就是用异或,但是js好像不支持这样的写法,所以下面的代码是java可以通过的写法:

class Solution {
    public void reverseString(char[] s) {
        int l = 0;
        int r = s.length - 1;
        while (l < r) {
            s[l] ^= s[r];  //构造 a ^ b 的结果,并放在 a 中
            s[r] ^= s[l];  //将 a ^ b 这一结果再 ^ b ,存入b中,此时 b = a, a = a ^ b
            s[l] ^= s[r];  //a ^ b 的结果再 ^ a ,存入 a 中,此时 b = a, a = b 完成交换
            l++;
            r--;
        }
    }
}

思考

这道题很简单,所以要知道这道题不是考语言自带的方法,而是要学会这个方法的原理。

541. 反转字符串 II

链接

题目链接

文章链接

第一想法

题目要求很简单,只要够2k个元素,就翻转前k个,想法是先写一个函数,翻转 start到end之间的元素,之后再for循环翻转,不过js不能直接操作字符串,所以我先把字符串转变为数组,最后再把数组变回字符串,代码如下:

function reverseStr(s: string, k: number): string {
    let arr=s.split("")
    //翻转start到end的数组元素
  const foo=(start:number,end:number,)=>{
      let left:number=start
      let right:number=end-1 //这里是end-1 原因是数组下标从0开始 翻转前两个 则下标是 0和1
      while(left<right){
        [arr[left],arr[right]]=[arr[right],arr[left]];
        left++
        right--
      }
  }
  for(let i=0;i<arr.length;i+=2*k){
   if(arr.length-i>=2*k) foo(i,i+k)
   else if (arr.length-i<k) foo(i,arr.length)
   else foo(i,i+k)
  }
  return arr.join("")
};

看完文章后的想法

文章的大体思路和我的一致,也是进行模拟,不过要把边界判断清楚,代码类型,所以就不展示了。

思考

这道题主要是让我们了解字符串的特性,js中由于无法直接操作字符串,所以我们先转换为数组,之后操作数组,最终把数组转变为字符串就可以了。同时这道题要考虑好边界条件就可以了。

剑指Offer 05.替换空格

链接

文章链接

题目链接

第一想法

第一眼看到就想用replaceAll这个方法,貌似使用ts时,力扣的版本好像不够:

image.png 所以我就换了一种写法,用replace和正则表达式解决这道题: 代码如下:

function replaceSpace(s: string): string {
    return s.replace(/\s/g,'%20')
};

下面是replaceAll的写法,不过语言是js

var replaceSpace = function(s) {
  return s.replaceAll(" ",'%20')
};

但是这道题感觉不是让咱们这样用的,所以我就想到了这个写法:

function replaceSpace(s: string): string {
    let arr:string[]=s.split(" ") //通过空格切分
    let str:string=''
    for(let i=0;i<arr.length;i++){
        if(i==arr.length-1) return str+arr[i]
        str+=arr[i]+'%20'
    }
    //其实可以没有这行 但是防止ts类型报错
    return str
};

看完文章后的想法

果然,文章没有用replace方法,而是用老生常谈的双指针的写法,代码如下:

function replaceSpace(s: string): string {
   let count:number=0
   for(let i=0;i<s.length;i++){
       if(s[i]==" ") count++
   }
   //这种写法从后往前填充和从前往后填充都是一样的
   let arr=new Array(s.length+count*2)
    let i=s.length-1
    let j=arr.length-1
    while(j>=0){
        if(s[i]==" "){
            arr[j]="0"
            arr[j-1]="2"
            arr[j-2]="%"
            j-=2
        }else{
            arr[j]=s[i]
        }
        i--
        j--
    }
    return arr.join("")
};

下面这种写法要从后往前填入,如果从前往后需要两层for循环,第二次需要给填充的位置腾位置:

function replaceSpace(s: string): string {
    let arr: string[] = s.split('');
    let spaceNum: number = 0;
    let oldLength: number = arr.length;
    for (let i = 0; i < oldLength; i++) {
        if (arr[i] === ' ') {
            spaceNum++;
        }
    }
    arr.length = oldLength + 2 * spaceNum;
    let cur: number = oldLength - 1;
    for (let i = arr.length - 1; i >= 0; i--, cur--) {
        if (arr[cur] !== ' ') {
            arr[i] = arr[cur]
        } else {
            arr[i] = '0';
            arr[--i] = '2';
            arr[--i] = '%';
        }
    }
    return arr.join('');
};

思考

这道题的解法有很多种,如果不使用任何内置方法的话则需要使用双指针,但是不同的代码写法会让这道题从后往前和从前往后填充是不一样的效果,所以在写题是要考虑清楚是从后往前填还是从前往后填。

151.翻转字符串里的单词

链接

文章链接

题目链接

第一想法

看到这道题,我首先想到了用split将字符串用' '切分,之后用双指针来翻转字符串同时去除多余的空格,代码如下:

function reverseWords(s: string): string {
  let arr:string[]=s.split(" ")
  let str:string=''
  //这里因为要到的输出,所以要从后往前
  for(let i=arr.length-1;i>=0;i--){
      if(arr[i]=='') continue
      let j=i-1
      str+=arr[i]
      //这里判断这个字符之前还有没有非空字符  如果有就需要给字符串添加上空格
      while(j>=0){
        if(arr[j]!=''){
            str+=' '
            break
        } 
        j--
      }
  }
  return str
};

看完文章后的想法

emmm,只能说还是想简单了,代码随想录中没有用任何内置方法写,纯自己手写思路为先去除多余空格,然后整个翻转,最后再把每个单词翻转。代码如下:

function reverseWords(s: string): string {
   //去除多余的空格
   let slow=0
   let arr=new Array()
   for(let i=0;i<s.length;i++){
     if(s[i]==' ') continue
     if(slow!=0) arr[slow++]=' '
     while(i<s.length&&s[i]!=' '){
         arr[slow++]=s[i++]
     }
   }
   //翻转函数
   const foo=(start:number,end:number)=>{
       let left:number=start
       let right:number=end-1
       while(left<right){
           [arr[left],arr[right]]=[arr[right],arr[left]]
           left++
           right--
       }
   }
   //全部翻转
   foo(0,arr.length)
   //翻转单词
   let start=0
   for(let i=0;i<=arr.length;i++){
         if(arr[i]==' '||i==arr.length){
             foo(start,i)
             start=i+1
         }
   }
   return arr.join("")

};

思考

原本我自己的想法是没有那么复杂,不用内置方法太麻烦了,原本想法是先把单词切出来,之后去除多余空格,看完文章后发现没用split,全部手写,惊呆我了。。。不过为了练习还是按照文章的思路写了一遍,理了一下思路,还不错。

剑指 Offer 58 - II. 左旋转字符串

链接

题目链接

文章链接

第一想法

第一想法是把前k个字符放到后面,所以我先把原来的字符串s变为s+s,那么只需要从k开始,寻找s.length的长度大小的字符串就可以了,代码如下:

function reverseLeftWords(s: string, n: number): string {
  let str:string=s+s
  let res:string=''
  for(let i=n;i<n+s.length;i++){
      res+=str[i]
  }
  return res
};

看完文章后的想法

因为先做的题,之后才看文章,看完文章的第一句话:

image.png 我就知道我得换思路了,还是用翻转字符串的方法,首先先翻转前k个,之后翻转k之后的,最后整体翻转,代码随想录的图片如下:

image.png 话不多说上代码:

function reverseLeftWords(s: string, n: number): string {
    const foo=(start:number,end:number)=>{
        let left:number=start
        let right:number=end-1
        while(left<right){
            [arr[left],arr[right]]=[arr[right],arr[left]];
            left++
            right--
        }
    }
    let arr:string[]=s.split("")
    //翻转前n个
    foo(0,n)
    //翻转n之后的
    foo(n,arr.length)
    //整体翻转
    foo(0,arr.length)
    return arr.join("")
};

思考

我觉得如果没有多余的条件的话,我觉得我的方法是不错的,代码随想录中的方法主要是让我熟悉翻转字符串的方法。整体上说不难。

今日总结

整体来说5道题如果没有多余的限制的话都不难,如果按照代码随想录中的限制的话,第四题也就是151.翻转字符串里的单词是比较麻烦的,写了一下熟悉思路,整体花费时间3.5小时