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

344.反转字符串

题目

求解

题目要求不给数组分配额外的空间,将数组第i个元素和倒数第i个交换位置即可

代码

var reverseString = function(s) {
    // 不能给数组分配额外的空间
    // 前面和后面的交换位置 
    let left = 0, right = s.length-1;
    while(left<right){
        [s[left],s[right]] = [s[right],s[left]];
        left++;
        right--;
    }
    return s;
};

541.反转字符串Ⅱ

题目

求解

当需要固定规律一段一段去处理字符串的时候,要想想如何在for循环的表达式上做做文章。

找规律:

  • arrayS.length < k时,反转所有字符,下标从0arrayS.length-1

  • k<= array.length < 2*k时,反转前k个字符,下标从0k-1

  • arrayS.length > 2*k时,先反转前k个字符

    再检测第2k+1个元素后面的字符满足上述哪种条件,当有多段字符需要反转时,两段相邻的字符串开始下标相差为2*k

因此设计for循环,循环体中下标更新为i += 2*k,即for(let i=0;i<arrayS.length;i+=2*k),对每段字符串进行检测并反转

使用双指针法进行部分反转,i即表示需要反转的开始位置,接下来确定结束位置right

  • 不足k个元素时,arrayS.length - i < k时,right = arrayS.length - 1

  • 有k个元素可以反转,right = i + k - 1

代码

var reverseStr = function(s, k) {
    let arrayS = s.split("");
    for(let i = 0;i<s.length;i += 2*k){
        // 如果有的话 前k个进行反转
        // 如果剩余少于k,反转剩余所有  right = s.length - i < k ? s.length -1 : i + k -1
        // 如果剩余>=k,反转前k个 
        let left = i, right = s.length - i < k ? s.length -1 : i + k -1;
        while(left<right){
            [arrayS[left],arrayS[right]] = [arrayS[right],arrayS[left]];
            left++;
            right--;
        }
    }
    return arrayS.join("")
};

剑指offer05.替换空格

题目

求解

很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。因为从前向后的话,每次移动都需要后移后面所有的元素,时间复杂度为O(n^2)。

  • 检测空格出现的次数

  • 使用快慢指针更新数组,即从后往前填充数组

    • fast指向新数组的尾部,slow指向旧数组的尾部

    • slow指向空格时arrayS[slow] ===' 'fast指向的地方需要添加三个元素

      arrayS[fast--] = '0';
      arrayS[fast--] = '2'; 
      array[fast--] = '%';
    • slow指向的不是空格,fast记录这个字符

      arrayS[fast--] = arrayS[slow--];

代码

var replaceSpace = function(s) {
    // 字符串转为数组
    let arrayS = s.split("");
    let spaceNum = 0;
    // 字符串中的空格变为%20,每有一个空格,数组长度需要+2
    // 计算空格的数量
    for(let i=0;i<s.length;i++){
        if(arrayS[i] === ' ') spaceNum++;
    }
    // 一个指向原数组末尾,一个指向新数组末尾
    let left = s.length - 1, right = s.length + 2 * spaceNum -1;
    // 替换空格 并后移相应元素
    // 如果出现空格,新数组分别加入% 2 0, 没出现空格,新数组拷贝旧数组元素
    while(left>=0){
        if(arrayS[left] === ' '){
            arrayS[right--] = '0';
            arrayS[right--] = '2';
            arrayS[right--] = '%';
            left--;
        }else{
            arrayS[right--] = arrayS[left--];
        }
    }
    return arrayS.join("");
};

151. 反转字符串中的单词

题目

 

求解

  • 将字符串转为数组let strArr = s.split("");

  • 首先需要去掉多余的空格,包括前导空格,尾随空格和单词间多余1个的空格。

    • 删除数组中的元素,使用双指针法,快指针遍历数组,慢指针记录新的数组

    • 检测前导空格,strArr[fast] === ' ' && fast === 0

    • 检测单词中多余的空格,strArr[fast] === ' ' && strArr[fast] === strArr[fast-1]

    • 删除前导、多余空格,strArr[slow++] = strArr[fast++]

    • 检测尾随空格,strArr[slow] === ' '

    • 删除尾随空格, strArr.length = slow-1;

  • 对整个字符串进行反转

  • 对每个单词进行反转,检测单词

    • 双指针法找到单词,i去遍历字符串,start记录单词第一个字母的位置

    • 单词最后一个字母的确定,当strArr[i] === ' '时,反转下标starti-1部分,并更新start = i+1

    • 由于字符串整体反转后,不存在尾随空格,最后一个单词不能用上述方法确定,最后一个单词的尾部为i === strArr.length

代码

var reverseWords = function(s) {
    let strArr = s.split("");
    // 首先需要去掉可能存在的多余空格,包括前导空格,尾随空格和单词间多于1个的空格
    removeExtraSpaces(strArr);
    // 先反转整个字符串,再反转单独的单词
    reverseWord(strArr,0,strArr.length-1);
    // start记录单词开始的地方,i去遍历字符串,遇到空格反转前面的单词。最后一个单词后没有空格,单独处理
    let start = 0;
    for(let i = 0;i<=strArr.length;i++){
        if(strArr[i] === ' ' || i === strArr.length){
            reverseWord(strArr,start,i-1);
            start = i+1;
        }
    }
    // 移除多余的空格 双指针法
    // 快指针遍历,慢指针为新数组坐标
    function removeExtraSpaces(strArr){
        let fast = 0, slow = 0;
        while(fast<strArr.length){
            // 删除开头的空格,和多余的空格
            // 即fast === 0, strArr[fast] === ' ' 和 strArr[fast] === strArr[fast-1] === ' '
            if(strArr[fast] === ' ' &&(fast === 0 || strArr[fast-1] === ' ')){
                fast++;
            }else{
                strArr[slow++] = strArr[fast++];
            }
        }
        // 末尾的空格
        strArr.length = strArr[slow-1] === ' '? slow-1:slow;
    }
    // 单个单词内部反转
    function reverseWord(strArr,start,end){
        let left = start,right = end;
        while(left<right){
            [strArr[left],strArr[right]] = [strArr[right],strArr[left]];
            left++;
            right--;
        }
    }
    return strArr.join("");
};

剑指offer58.左旋转字符串

题目

求解

方法1:先反转前n个字符,再反转第n个字符后的所有字符,再反转整体

方法2:将第n个字符后的字符整体前移(将最后一个插到最前面)

需要调整len-n次,每次将最后一个字符调整到最前面,其中let len = s.length;,采用字符串拼接的形式。let len = s.length;需要事先记录,因为在拼接的过程中,字符串的长度会发生变化

代码

// 方法1
var reverseLeftWords = function(s, n) {
    // 先反转前n个,再反转n个后面的,再反转整体
    function reverse(strArr,start,end){
        let left = start, right = end;
        while(left<right){
            [strArr[left],strArr[right]] = [strArr[right],strArr[left]];
            left++;
            right--;
        }
    }
    let sArr = s.split("");
    reverse(sArr,0,n-1);
    reverse(sArr,n,sArr.length-1);
    reverse(sArr,0,sArr.length-1);
    return sArr.join("");
};
// 方法2
var reverseLeftWords = function(s, n) {
    let len = s.length;
    let i = 0;
    while(i<len-n){
        // 将最后一个字符提到最前面,采用字符串拼接的形式
        s = s[len-1] + s;
        i++;
    }
    return s.slice(0,len);
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值