代码随想录算法训练营第八天| 344.反转字符串、541.反转字符串 II、54.替换数字、151.翻转字符串里的单词

344.反转字符串

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

文档讲解:代码随想录/反转字符串

视频讲解:视频讲解-反转字符串

状态:已完成(1遍)

解题过程 

看到题目的第一想法

 我的第一想法是双指针,一左一右两个指针,指向的字母调换位置。

/**
 * @param {character[]} s
 * @return {void} Do not return anything, modify s in-place instead.
 */
var reverseString = function(s) {
    if(s.length == 1) return s;
    let left = 0,right = s.length -1;
    while(left<right){
        [s[left],s[right]] = [s[right],s[left]]
        left++;
        right--;
    }
    return s;
};

 提交没有问题,来看看代码随想录怎么说。

看完代码随想录之后的想法 

这道题还是比较简单的,反转的思维跟数组里的有序数组的平方和比较类似。

不过文字讲解的答案看上去还是比较简洁:

/**
 * @param {character[]} s
 * @return {void} Do not return anything, modify s in-place instead.
 */
var reverseString = function(s) {
    //Do not return anything, modify s in-place instead.
    reverse(s)
};

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

总结

这道题总的来说跟操作数组没有什么区别,较为简单。


 541.反转字符 II

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

文档讲解:代码随想录/反转字符 II

视频讲解:视频讲解-反转字符串 II

状态:已完成(1遍)

解题过程  

看到题目的第一想法

剩余字符有三种情况,那就在for循环里来三个if,每种的处理情况不同,但反转的部分都类似,把要反转的部分取出,反转,再放回去。

/**
 * @param {string} s
 * @param {number} k
 * @return {string}
 */
var reverseStr = function(s, k) {
    const sArr = s.split('');
    let len = sArr.length;
    for(let i = 0;i<len;){
        if(len<i+k){
            let sliceArr = sArr.slice(i,len).reverse();//把要反转的部分切出来,再反转一下
            sArr.splice(i,len-i,...sliceArr);//再把反转好的部分给替换掉
            i = len;
        }else if(len>=i+k&&len<i+2*k){
            let sliceArr = sArr.slice(i,i+k).reverse();
            sArr.splice(i,k,...sliceArr);
            i = len;
        }else if(len>=i+2*k){
            let sliceArr = sArr.slice(i,i+k).reverse();
            sArr.splice(i,k,...sliceArr);
            i+=2*k;
        }
    }
    let ans = sArr.join('');
    return ans;
};

提交也没有问题,继续看看代码随想录。 

 看完代码随想录之后的想法 

步骤怎么这么短,哥们错付了。。。

确实不用对剩余字符小于2k但大于k个的情况和大于2k的情况做区分,两者都是要反转前k个字符串的,而我也忘记了我最爱的?:可以在这里用上,两种情况只有reverse的长度需要区分,这样判断起来确实更快一些。这样的用法搭配上不用reverse的初始写法甚至更简便。

讲解代码如下:

/**
 * @param {string} s
 * @param {number} k
 * @return {string}
 */
var reverseStr = function(s, k) {
    const len = s.length;
    let resArr = s.split(""); 
    for(let i = 0; i < len; i += 2 * k) {  // 每隔 2k 个字符的前 k 个字符进行反转
        let l = i - 1, r = i + k > len ? len : i + k;
        while(++l < --r) [resArr[l], resArr[r]] = [resArr[r], resArr[l]];
    }
    return resArr.join("");
};

总结

像这题一样,成段成段的往后跳的话,for循环的i可以不用i++,而是也跟这着段的跳。同时善用条件运算符。


 卡码网:54.替换数字

题目链接:卡码网:54.替换数字

文档讲解:代码随想录/卡码网·替换数字

视频讲解:无

状态:已完成(1遍)

解题过程  

看到题目的第一想法

拆成数组,遍历,有数字就把它换成"number",最后再转换成字符串。

不是哥们,一通操作猛如虎,输入完了运行告诉我没登录不给运行,登录完了之后我代码没了????

const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
})

function main() {
    const num0 = "0".charCodeAt();
    const num9 = "9".charCodeAt();
    const a = "a".charCodeAt();
    const z = "z".charCodeAt();
    function isAZ(str) {
        return str >= a && str <= z;
    }
    function isNumber(str) {
        return str >= num0 && str <= num9;
    }
    rl.on("line", (input) => {
        const inputArr = input.split("");
        for (let i = 0; i < inputArr.length; i++) {
            let ascii = input[i].charCodeAt();
            if (isNumber(ascii)) {
                inputArr[i] = "number";
            }
        }
        console.log(inputArr.join(""));
    })
}

main();

运行提交都没问题。 

 看完代码随想录之后的想法 

真的需要这样写吗,直接把数组里的数字改成“number”应该也没有任何问题吧?有没有大神能解答一下。

讲解代码如下:

const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
})

function main() {
    const num0 = "0".charCodeAt();
    const num9 = "9".charCodeAt();
    const a = "a".charCodeAt();
    const z = "z".charCodeAt();
    function isAZ(str) {
        return str >= a && str <= z;
    }
    function isNumber(str) {
        return str >= num0 && str <= num9;
    }
    rl.on("line", (input) => {
        let n = 0;
        for (let i = 0; i < input.length; i++) {
            const val = input[i].charCodeAt();
            if (isNumber(val)) {
                n+= 6;
            }
            if (isAZ(val)) {
                n++;
            }
        }
        const ans = new Array(n).fill(0);
        let index = input.length - 1;
        for (let i = n - 1; i >= 0; i--) {
            const val = input[index].charCodeAt();
            if (isAZ(val)) {
                ans[i] = input[index];
            }
            if (isNumber(val)) {
                ans[i] = "r";
                ans[i - 1] = "e";
                ans[i - 2] = "b";
                ans[i - 3] = "m";
                ans[i - 4] = "u";
                ans[i - 5] = "n";
                i -= 5;
            }
            index--;
        }
        console.log(ans.join(""));
    })
}

main();

总结

这道题属实是没有想到用到双指针上面去,不过也算是学习了一种思路了。


151.翻转字符串里的单词

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

文档讲解:代码随想录/翻转字符串里的单词

视频讲解:视频讲解-翻转字符串里的单词

状态:已完成(1遍)

解题过程 

看到题目的第一想法

 来个双指针,一左一右往中间夹,遇到空字符串就把它删了,只有左右指针指向的值都不是空字符串的时候才交换两指针的值。

/**
 * @param {string} s
 * @return {string}
 */
var reverseWords = function(s) {
    const sArr = s.split(" ");
    let len = sArr.length;
    let left = 0,right = len-1;
    while(left<right){
        while(sArr[left]=="") sArr.splice(left,1);
        while(sArr[right]=="")sArr.splice(right,1);
        [sArr[left],sArr[right]] = [sArr[right],sArr[left]];
        left++;
        right--;
    }
    const ans = sArr.join(" ");
    return ans;
};

直接当小丑,运行都通不过,debug了一波又一波,发现了如下问题:

  1. 如果查到空字符串,left可以splice,但是同时right也得--;同样right这边如果splice了的话也得--;
  2. 如果最后指针在中间是几个空字符串,那么会让最中间的已经交换过的再交换回来;
  3. 如果left和right相等了,但是最后相等的时候是个空字符串,得把他删掉。

修改后的代码如下: 

/**
 * @param {string} s
 * @return {string}
 */
var reverseWords = function (s) {
    const sArr = s.split(" ");
    let len = sArr.length;
    let left = 0, right = len - 1;
    while (left < right) {
        while (sArr[left] == "") {
            sArr.splice(left, 1);
            right--;//注意这里要及时将right减一
        }
        while (sArr[right] == "") {
            sArr.splice(right, 1);
            right--;//注意这里要及时将right减一
        };
        if (left < right) {
            [sArr[left], sArr[right]] = [sArr[right], sArr[left]];
            left++;
            right--;
        }
    }
    if(left==right&&sArr[left]=="") sArr.splice(left,1)
    const ans = sArr.join(" ");
    return ans;
};

提交终于没问题了。。。debug了半小时。。。

看完代码随想录之后的想法 

卡哥的思想是去除多余的空格,翻转字符串,再翻转单词,确实也是学到了新思路。

/**
 * @param {string} s
 * @return {string}
 */
 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--;
  }
}

总结

我感觉这道题还是我自己想出来的思路比较容易理解一点哈哈,不过先翻转所有字符串再反转单词内的字符串也很牛逼。

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值