字符串篇:344.反转字符串、 541. 反转字符串II、剑指Offer 05.替换空格、151.翻转字符串里的单词、剑指Offer58-II.左旋转字符串

提示:努力生活,开心、快乐的一天


344.反转字符串

题目链接:344.反转字符串

💡解题思路

  1. 采用双指针,前后两个指针,一个指向最前面一个指向最后面两个指针数值翻转后,两个指针再向内移动

🤔遇到的问题

  • 移动时忘记移动后面的指针了

💻代码实现

双指针

var reverseString = function (s) {
    //双指针,一个指向数组头,一个指向数组尾
    let len = s.length
    //i与j同步移动,所以此处限制条件可以只限制i
    for (let i = 0, j = len - 1; i < len / 2; i++, j--) {
        //两个数反转
        [s[i], s[j]] = [s[j], s[i]]
    }
};

🎯题目总结

  • 对于字符串,我们定义两个指针(也可以说是索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素
  • 如果题目关键的部分直接用库函数就可以解决,建议不要使用库函数;如果库函数仅仅是 解题过程中的一小部分,并且你已经很清楚这个库函数的内部实现原理的话,可以考虑使用库函数。

541. 反转字符串II

题目链接:541. 反转字符串II

💡解题思路

  • 首先确认需要翻转的数组,翻转过程与前面的翻转字符串基本一致
  • 数组的遍历,i 每次移动 2 * k ,会更加的高效

🤔遇到的问题

  • 在翻转数组的时候,没有对数组进行循环,只把头尾的两个数进行了翻转

💻代码实现

遍历+双指针

var reverseStr = function (s, k) {
    let resArr = s.split('');
    let len = s.length
    //在遍历字符串的过程中,i 每次移动 2 * k 就可以
    for (let i = 0; i < len; i += 2 * k) {
        //翻转字符串中使用双指针
        let l = i;
        let r = i + k - 1 > len ? len : i + k - 1
        //将数组中的数进行翻转
        //一前一后俩俩翻转,左右指针移动
        while (l < r) {
            [resArr[l], resArr[r]] = [resArr[r], resArr[l]]
            l++;
            r--;
        }
    }
    return resArr.join("")
};

🎯题目总结

遍历的时候,不一定i++去循环、也需要根据题目进行变通,就比如该题,需要i+=2*k。
数组翻转需要循环着,另外后面的指针需要往后移动一位-1

剑指Offer 05.替换空格

题目链接:剑指Offer 05.替换空格

💡解题思路

  • 确认字符串中空格的个数
  • 扩充数组,扩充的个数是空格填入的%20后的个数,新数组长度为strArr.length+count*2
  • 双指针协助进行空格的填充
    主要为,left(前指针)原数组的末端right(后指针)新数组的末端当strArr[left]为空格时,right向前移动三个位置,并分别填入02%,如果不为空格,将left的值赋给right

🤔遇到的问题

  • right指向新数组的末端判断错了

💻代码实现

双指针

var replaceSpace = function(s) {
    let strArr = Array.from(s)
    let len = strArr.length
    //统计字符串中,空格的个数
    count=0
    for(let i =0;i<len;i++){
        if(strArr[i]===' '){
            count++
        }
    }
    //扩充数组到每个空格替换成"%20"之后的大小
    //left指向旧数组的末端
    //right指向新数组的末端
    let left = len-1
    let right = len + count * 2 - 1
    //判断left是否为空,引导right向前移动
    while(left>=0){
        if(strArr[left]===' '){
            strArr[right--] = '0';
            strArr[right--] = '2';
            strArr[right--] = '%';
            left--
        } else {
            //不为空时,将前面指针的数据,给到后面指针
            strArr[right--] = strArr[left--]
        }
    }
    return strArr.join('')
};

🎯题目总结

为什么要从后向前填充,从前向后填充不行么?

  • 不用申请新数组。
  • 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。

151.翻转字符串里的单词

题目链接:151.翻转字符串里的单词

💡解题思路

  • 可先转化为数组
  • 去除多余空格:字符串头部空格、字符串尾部空格、字符串中两个连着的空格,采用快慢指针,一个方向移动
  • 整体翻转字符串,采用左右指针,对向移动
  • 翻转字符串中的每个单词,通过判断空格的方式,确定一个可翻转的单词

🤔遇到的问题

  • 数组去重的条件没有弄清楚
  • 忘记移除尾部的空格
  • 翻转时候,左右指针对向移动,一个++,一个–

💻代码实现

快慢双指针+前后双指针

var reverseWords = function (s) {
    let strArr = Array.from(s)
    //去除多余空格
    removeExtraSpaces(strArr)
    //第一次翻转,整个数组翻转
    reverse(strArr, 0, strArr.length - 1)
    //第二次翻转,每个单词翻转
    //每个单词的起始位置
    let start = 0
    for (let i = 0; i <= strArr.length; i++){
        //i遇到空格,一个单词从star到i-1处
        if (strArr[i] === ' ' || i === strArr.length) {
            reverse(strArr, start, i - 1)
            //修改下一个单词的起始位置
            start = i+1
        }
    }
    return strArr.join('');
};
//数组去重
let removeExtraSpaces = function (strArr) {
    //快慢两个指针,快指针指向有意义的值,慢指针指向需要更替的值
    let len = strArr.length;
    let fast = 0
    let slow = 0
    while (fast < len) {
        //移除首位空格
        //移除中间2个空格的情况
        if (strArr[fast] === ' ' && (fast === 0 || strArr[fast - 1] === ' ')) {
            fast++
        } else {
            strArr[slow] = strArr[fast]
            fast++
            slow++
        }
    }
    //移除最后一个空格
    strArr.length = strArr[slow - 1] === ' ' ? slow - 1 : slow
}
//数组翻转
//start:翻转的起始位置
//end:翻转的结束位置
let reverse = function (strArr, start, end) {
    //双指针翻转
    let left = start
    let right = end
    while (left < right) {
        //交换
        [strArr[left], strArr[right]] = [strArr[right], strArr[left]]
        left++
        right--
    }
}

🎯题目总结

解题思路了解清楚,各种边界的处理

  • 移除多余空格
  • 将整个字符串反转
  • 将每个单词反转

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

题目链接:剑指Offer58-II.左旋转字符串

💡解题思路

  • 将整个字符串进行反转
  • N的位置发生了变化
  • 将N之前的部分进行反转
  • 将N之后的部分进行反转

🤔遇到的问题

  • 整体翻转后,N发生了变化,再进行后面的反转时,N的位置找错啦

💻代码实现

双指针

var reverseLeftWords = function(s, n) {
    strArr = Array.from(s)
    let len = strArr.length
    //翻转整个字符串
    reverse(strArr, 0, len - 1)
    //翻转后的字符串,n变成了从后向前数
    //翻转后,前面一部分的字符串
    reverse(strArr, 0, len - n - 1)
    //翻转后,后面一部分的字符串
    reverse(strArr,len-n,len-1)
    return strArr.join('')
};
let reverse = function (strArr, start, end) {
    //双指针翻转
    let left = start
    let right = end
    while (left < right) {
        //交换
        [strArr[left], strArr[right]] = [strArr[right], strArr[left]]
        left++
        right--
    }
}

🎯题目总结

反转、反转再反转,也可以用slice函数进行解题,特殊注意:整体翻转后的N的值域原本的不同了

🎈今日心得

今天的题中,主攻各种反转:

  • 在344.反转字符串 (opens new window),第一次讲到反转一个字符串应该怎么做,使用了双指针法。
  • . 反转字符串II (opens new window),这里开始给反转加上了一些条件,当需要固定规律一段一段去处理字符串的时候,要想想在for循环的表达式上做做文章。
  • 后来在151.翻转字符串里的单词 (opens new window)中,要对一句话里的单词顺序进行反转,发现先整体反转再局部反转 是一个很妙的思路。
  • 最后剑指Offer58-II.左旋转字符串,该题则是先局部反转再 整体反转,与151.翻转字符串里的单词 (opens new window)类似,但是也是一种新的思路。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值