leetcode每天5题-Day33

1.反转字符串

344. 反转字符串-简单
b站视频-代码随想录
要求:原地修改,空间复杂度为O(1)

该题也是双指针法的一个经典应用。
思路:首尾交换

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

代码随想录版👇

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]];
};

2.反转字符串II

541. 反转字符串 II-简单
b站视频-代码随想录
解题思路:模拟,按照题目中的反转规则反转字符串即可
重点:用i遍历字符串时,不是i++,而是i+=2k

var reverseStr = function(s, k) {
    // 把字符串转化成字符串数组sArr
    let sArr = s.split("");
    for(let i = 0;i < s.length; i += 2*k){
        let l = i - 1,r = i + k > s.length?s.length:i + k;
        while(++l < --r){
            [sArr[l],sArr[r]] = [sArr[r],sArr[l]];
        }
    }
    return sArr.join("");
};

3.替换空格

剑指 Offer 05. 替换空格-简单
双指针
思路:先统计字符串中空格的数量,然后根据这个数量把数组大小扩充为替换空格后的大小,最后双指针从后向前遍历,遇到空格就将其替换成%20

注:从后向前填充元素,避免了从前先后填充元素要来的 每次添加元素都要将添加元素之后的所有元素向后移动。

var replaceSpace = function(s) {
    // 将s转为字符串数组sArr
    let sArr = Array.from(s);
    // 统计字符串中空格的数量
    let count = 0;
    for(const c of sArr){
        if(c === ' ') count++;
    }
    let l = s.length - 1;
    let r = s.length + 2*count -1;
    while(l >= 0){
        if(sArr[l] == ' '){
            sArr[r--] = '0';
            sArr[r--] = '2';
            sArr[r--] = '%';
            l--;
        }else{
            sArr[r--] = sArr[l--];
        }
    }
    return sArr.join('');
};

时间复杂度:O(n)
空间复杂度:O(1)

4.反转字符串中的单词

151. 反转字符串中的单词-中等
b站视频-代码随想录
思路:移除多余空格—>将整个字符串反转—>将每个单词反转
移除多余空格时,使用双指针,思路与数组那一章节leetcode27.移除元素一样

var removeExtraSpaces = function(sArr) {
    let slow = 0,fast = 0;
    while(fast < sArr.length){
        // 移除开始位置和重复的空格
        if(sArr[fast] === ' ' && (fast === 0 || sArr[fast - 1] === ' ')){
            fast++;
        }else{
            sArr[slow++] = sArr[fast++];
        }
    }
    // 移除末尾空格
    sArr.length = sArr[slow - 1] === ' '?slow - 1:slow;
};
var reverse = function(s,l,r){
    while(l < r){
        [s[l],s[r]] = [s[r],s[l]];
        l++,r--;
    }
};
var reverseWords = function(s) {
    const sArr = Array.from(s);
    removeExtraSpaces(sArr);
    // 将整个字符串反转
    reverse(sArr,0,sArr.length - 1);
    // 反转每个单词
    let start = 0;
    for(let i = 0;i <= sArr.length;i++){
        if(sArr[i] === ' ' || i === sArr.length){
            reverse(sArr,start,i - 1);
            start = i + 1;
        }
    }
    return sArr.join('');
};

时:O(n)
空:O(1)
感觉这道题还是比较复杂的,估计做个两三遍才能自己做出来..

5.左旋转字符串

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

超时版

var reverseLeftWords = function(s, n) {
    let sArr = Array.from(s);
    while(n > 0){
    let num = sArr.shift();
        sArr.push(num);
        n--;
    }
    return sArr.join('');
};

超出时间限制…
思路:和上一题一样,整体反转+两次局部反转

根据思路自己写的

var reverse = function(s,l,r) {
    while(l < r){
        [s[l],s[r]] = [s[r],s[l]];
        l++,r--;
    }
    return;
}
var reverseLeftWords = function(s, n) {
    let sArr = Array.from(s);
    // 反转整个字符串
    reverse(sArr,0,sArr.length-1);
    // 反转前 sArr.length-n 个字符
    reverse(sArr,0,sArr.length-n-1);
    // 反转后n个字符
    reverse(sArr,sArr.length-n,sArr.length-1);
    return sArr.join('');
};

时:O(n)
空:O(1)

代码随想录版

var reverseLeftWords = function(s, n) {
  const length = s.length;
  let i = 0;
  while (i < length - n) {
    s = s[length - 1] + s;
    i++;
  }
  return s.slice(0, length);
};

6.实现 strStr()

28. 找出字符串中第一个匹配项的下标-简单
本题是KMP 经典题目。
“在一个串中查找是否出现过另一个串,这是KMP的看家本领。”
KMP的经典思想就是:当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。

b站视频-代码随想录

前缀表是什么?
记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。
最长相等前后缀?
在这里插入图片描述
前缀表其实就是next数组

前缀表统一减一

var strStr = function (haystack, needle) {
    if (needle.length === 0)
        return 0;

    const getNext = (needle) => {
        let next = [];
        let j = -1;
        next.push(j);

        for (let i = 1; i < needle.length; ++i) {
            while (j >= 0 && needle[i] !== needle[j + 1])
                j = next[j];
            if (needle[i] === needle[j + 1])
                j++;
            next.push(j);
        }

        return next;
    }

    let next = getNext(needle);
    let j = -1;
    for (let i = 0; i < haystack.length; ++i) {
        while (j >= 0 && haystack[i] !== needle[j + 1])
            j = next[j];
        if (haystack[i] === needle[j + 1])
            j++;
        if (j === needle.length - 1)
            return (i - needle.length + 1);
    }

    return -1;
};

前缀表统一不减一

var strStr = function(haystack, needle) {
    // 求next数组,即前缀表
    const getNext = (needle) => {
        let next = [];
        let j =0;
        next.push(j);

        for(let i = 1;i < needle.length;i++){
            while(j > 0 && needle[i] !== needle[j]){
            // j回退
                j = next[j-1];
            }
            if(needle[i] === needle[j]){
                j++;
            }
            // 更新next数组
            next.push(j);
        }
        return next;
    }

    let next = getNext(needle);
    let j = 0;
    for(let i = 0;i < haystack.length;i++){
        while(j > 0 && haystack[i] !== needle[j]){
            j = next[j-1];
        }
        if(haystack[i] === needle[j]){
            j++;
        }
        if(j === needle.length){
            return i-needle.length + 1;
        }
    }
    return -1;
};

7.重复的子字符串

459. 重复的子字符串-简单
b站视频-代码随想录
①暴力解法O(n²)
字串起始位置一定是0,只需一层for循环找子串结尾位置,一层for循环比较主串与子串。
②移动匹配
思路:如果该字符串由子串组成,那它就满足前半部分与后半部分相等的情况。拼接字符串,然后看去除首尾字符的s+s中是不是存在s
③KMP解法
重点:在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串
推导过程👉代码随想录

var repeatedSubstringPattern = function(s) {
    if(s.length === 0) return false;

    const getNext = (s) => {
        let next = [];
        let j =0;
        next.push(j);
        for(let i = 1;i < s.length;i++){
            while(j > 0 && s[i] !== s[j]){
                j = next[j - 1];
            }
            if(s[i] === s[j]){
                j++;
            }
            next.push(j);
        }
        return next;
    }

    let next = getNext(s);
    if(next[next.length-1] !== 0 && s.length % (s.length - next[next.length-1]) === 0){
        return true;
    }
    return false;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值