✅✅代码随想录算法训练营Day8

112 阅读3分钟

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

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第11篇文章 点击查看文章详情 🚀🚀

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情🚀🚀

前言

今天一下子安排了五道题,不仅我吃不消了,文章的标题也吃不消了,这些字都打不上去了。 希望明天卡哥可以手下留情~😨😨😨

344. 反转字符串 - 力扣(LeetCode)

难度:🔥🔥

image.png

双指针

var reverseString = function(s) {
    let len = s.length;
    let l = 0;
    let r = len-1;
    while(l < r){
        [s[l],s[r]] = [s[r],s[l]];
        l++;
        r--;
    }
    return s;

};

这里我们要尝试用底层一点的东西去实现,如果仅仅是用reverse这个api的话,直接就完事了,这样做的话百分之百达不到面试官的要求的。

另外一点就是这里用双指针去实现也挺简单的~

541. 反转字符串 II - 力扣(LeetCode)

难度:🔥🔥🔥

image.png

双指针

var reverseStr = function(s, k) {
    let len = s.length;
    let res= s.split('');
    for(let i = 0;i < len;i += 2*k){
        let l = i-1;
        let r = i+k;
        r = i+k > len ? len : i+k;
        while(++l<--r){
            [res[l],res[r]] = [res[r],res[l]];
        }
    }
    return res.join('')
};

难点

前k的处理逻辑

肯定有不少人为了处理逻辑:每隔2k个字符的前k的字符,写了一堆逻辑代码或者再搞一个计数器,来统计2k,再统计前k个字符。

其实在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。

 for(let i = 0;i < len;i += 2*k){
 }

split和join方法的理解

刚刷的这里的时候,对splitjoin很懵!!!

  • split: 使用指定的分隔符字符串将一个字符对象分割成子字符串数组,以一个指定的分割字串来决定每个拆分的位置。

    这是字符串的api

    下面是容易弄混的split的结果

    let q = 'wearehappy'
    let arr = q.split('');
    let brr = q.split(' ')
    let crr = q.split()
    
    console.log(arr,'arr');  
    console.log(brr,'brr');
    console.log(crr,'crr');
    console.log(q,'q');
    

    image.png 所以我们一般用split('')将每个字符进行分隔成数组

    并且split不会改变原来的字符串

  • join:用于把数组中的所有元素放入一个字符串。

join易混淆的结果

let s = ['a','p','p','l','e']
let res = s.join();
let arr = s.join('')
let brr = s.join(' ')

console.log(res,'res');
console.log(arr,'arr');
console.log(brr,'brr');
console.log(s,'s');

// join('')将数组元素无缝拼接

// join(' ') 将数组元素以空格分割

// join()将数组每个元素都转为字符串,用法等同于toString()  默认以逗号分隔

image.png

根据结果,所以我们一般用join('')去实现数组转字符串

并且join()不会改变原来的数组

最后的判断

当遍历到最后一组时,也要符合题目的要求:

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

在这里,三目运算符可以很好的进行体现:

    let l = i-1;
    let r = i+k;
    r = i+k > len ? len : i+k;

剑指 Offer 05. 替换空格 - 力扣(LeetCode)

难度:🔥🔥🔥

image.png

api解法

    let res = s.split(' ');
    let newS = res.join('%20');
    return newS

正则解法

     return s.replace(/ /g, "%20");

双指针

 let len = s.length;
    let res = s.split('');
    let count = 0;
    for(let i = 0; i < len;i++){
        if(res[i] == ' ')
            count++;
    }
    let l = len - 1;
    let r = len - 1 + count*2;
    while(l >= 0){
        if(res[l] !== ' '){
            res[r--] = res[l--];
        }
        else{
            res[r--] = '0';
            res[r--] = '2';
            res[r--] = '%';
            l--
        }
    }
    return res.join('')

难点

数组不会存在操作空指针的情况

    let l = len - 1;
    let r = len - 1 + count*2;

这里r已经大于了数组的长度了,但依旧可以继续操作。

151. 反转字符串中的单词 - 力扣(LeetCode)

难度:🔥🔥🔥🔥

image.png

api

return s.trim().split(/\s+/).reverse().join(' ');

快慢指针

   var reverseWords = function(s) {
   // 字符串转数组
   const strArr = Array.from(s);
   // 移除多余空格
   removeExtraSpaces(strArr);
   // 翻转
   reverse(strArr, 0, strArr.length - 1);

   let start = 0;

   for(let i = 0; i <= strArr.length; i++) {
     if (strArr[i] === ' ' || i === strArr.length) {
       // 翻转单词
       reverse(strArr, start, i - 1);
       start = i + 1;
     }
   }

   return strArr.join('');
};

// 删除多余空格
function removeExtraSpaces(strArr) {
  let slowIndex = 0;
  let fastIndex = 0;

  while(fastIndex < strArr.length) {
    // 移除开始位置和重复的空格
    if (strArr[fastIndex] === ' ' && (fastIndex === 0 || strArr[fastIndex - 1] === ' ')) {
      fastIndex++;
    } else {
      strArr[slowIndex++] = strArr[fastIndex++];
    }
  }

  // 移除末尾空格
  strArr.length = strArr[slowIndex - 1] === ' ' ? slowIndex - 1 : slowIndex;
}

// 翻转从 start 到 end 的字符
function reverse(strArr, start, end) {
  let left = start;
  let right = end;

  while(left < right) {
    // 交换
    [strArr[left], strArr[right]] = [strArr[right], strArr[left]];
    left++;
    right--;
  }
}
};

这个题,就感觉很难受,只用api嫌弃它太简单了,不用api纯手写出来这些功能,又比较难~😡😡😡

剑指 Offer 58 - II. 左旋转字符串 - 力扣(LeetCode)

难度:🔥🔥🔥

image.png

固定搭配

var reverseLeftWords = function(s, n) {
    const fn = (res,l,r) => {
        while(l < r){
            [res[l],res[r]] = [res[r],res[l]];
            l++;
            r--;
        }
    }
    let len = s.length;
    let res = s.split('');
    fn(res,0,n-1);
    fn(res,n,len-1);
    fn(res,0,len-1)
    return res.join('')
};

害,这个题的思路也奇奇怪怪,第一次刷一般想不到

难点

实现思路

  1. 反转区间为前n的子串
  2. 反转区间为n到末尾的子串
  3. 反转整个字符串

image.png

总结下来就是:

先转左半边

再右半边

最后再一起转

小结

今天刷题的体验不太好,一个是字符串这边固定的题型不多,api也多,就比较乱。然后今天的任务量也比较多,脑子要烧掉了~

  • 反转字符串:(今天的主线)
while(l < r){
    [s[l],s[r]] = [s[r],s[l]];
    l++; 
    r--;
}

经常利用双指针lr进行交换

  • 加深了对splitjoin的理解

希望明天不要再来五道算法题了 😨😨😨