✅✅代码随想录算法训练营Day9 || 28. 实现 strStr(),剑指 Offer II 019. 最多删除一个字符得到回文

116 阅读3分钟

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

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

前言

image.png

上午的我发现今天竟然只有一道题,以为能够在两个小时之内就写完,然后去写项目去。

没想到,今天这一题更比六题强~~~ 😨😨😨

kmp我是真看不懂了~害

28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)

image.png

暴力解法

这题暴力解法太香了,kmp就算了吧

var strStr = function(haystack, needle) {
    let len1 = haystack.length;
    let len2 = needle.length;

    for(let i = 0;i < len1; i++){
        for(let j = 0;j < len2;j++){
            if(haystack[i+j] == needle[j]){
                if(j == len2-1){
                    return i;
                }
                continue;
            }
            else{
                break;
            }
        }
    }
    return -1
};

剑指 Offer II 019. 最多删除一个字符得到回文 - 力扣(LeetCode)

这个题算是今天的补偿了。

后面就开始小结一部分修言老师关于字符串这题型的讲解吧

判断一个字符串是回文字符串

回文字符串,就是正着读和倒着读都一🐱一样的字符串,比如这样的:

'yessey'

其中一个最简单的方法就是直接反转之后,看看反转之后的字符串是否和原先的字符串相等

function isPalindrome(str) { 
// 先反转字符串
const reversedStr = str.split('').reverse().join('') 
// 判断反转前后是否相等 
return reversedStr === str
}

同时,回文字符串还有另一个特性:如果从中间位置“劈开”,那么两边的两个子串在内容上是完全对称的。因此我们也可以结合对称性来做判断:

function isPalindrome(str) { 
// 缓存字符串的长度 
const len = str.length 
// 遍历前半部分,判断和后半部分是否对称
for(let i=0;i<len/2;i++) { 
    if(str[i]!==str[len-i-1]){ 
    return false
    }
 } 
return true
}

和昨天的双指针进行反转字符串的思路是一样的。

回到前面的题目

image.png

双指针+判断回文

思路分析

如果在字符串题干中有“回文”关键字,那么做题时脑海中一定要冒出两个关键字——对称性 和 双指针

回到这道题上来,我们首先是初始化两个指针,一个指向字符串头部,另一个指向尾部:

image.png 如果两个指针所指的字符恰好相等,那么这两个字符就符合了回文字符串对对称性的要求,跳过它们往下走即可。如果两个指针所指的字符串不等,比如这样:

image.png

那么就意味着不对称发生了,意味着这是一个可以“删掉试试看”的操作点。我们可以分别对左指针字符和右指针字符尝试进行“跳过”,看看区间在 [left+1, right] 或 [left, right-1] 的字符串是否回文。如果是的话,那么就意味着如果删掉被“跳过”那个字符,整个字符串都将回文:

image.png

比如说这里我们跳过了 b,[left+1, right] 的区间就是 [2, 2],它对应 c 这个字符,单个字符一定回文。这样一来,删掉 b 之后,左右指针所指的内部区间是回文的,外部区间也是回文的,可以认为整个字符串就是一个回文字符串了。

代码实现


const validPalindrome = function(s) {
    // 缓存字符串的长度
    const len = s.length

    // i、j分别为左右指针
    let i=0, j=len-1
    
    // 当左右指针均满足对称时,一起向中间前进
    while(i<j&&s[i]===s[j]) {
        i++ 
        j--
    }
    
    // 尝试判断跳过左指针元素后字符串是否回文
    if(isPalindrome(i+1,j)) {
      return true
    }
    // 尝试判断跳过右指针元素后字符串是否回文
    if(isPalindrome(i,j-1)) {
        return true
    }
    
    // 工具方法,用于判断字符串是否回文
    function isPalindrome(st, ed) {
        while(st<ed) {
            if(s[st] !== s[ed]) {
                return false
            }
            st++
            ed--
        } 
        return true
    }
    
    // 默认返回 false
    return false 
};

收获

今天的收获不在卡哥这边了,在修言老师这边,昨天卡哥那边题目多,今天少但巨难。

体验感好差~

没办法,自己还是太菜了~

匹配字符串

 for(let i = 0;i < len1; i++){
        for(let j = 0;j < len2;j++){
            if(haystack[i+j] == needle[j]){
                if(j == len2-1){
                    return i;
                }
                continue;
            }
            else{
                break;
            }
        }
    }

注意里面if(haystack[i+j] == needle[j])

反转字符串api的固定搭配

// 定义被反转的字符串
const str = 'juejin'
// 定义反转后的字符串 
const res = str.split('').reverse().join('') 
console.log(res) // nijeuj

判断回文字符串

api法:

function isPalindrome(str) { 
// 先反转字符串
const reversedStr = str.split('').reverse().join('') 
// 判断反转前后是否相等 
return reversedStr === str
}

双指针法


function isPalindrome(str) { 
// 缓存字符串的长度 
const len = str.length 
// 遍历前半部分,判断和后半部分是否对称
for(let i=0;i<len/2;i++) { 
    if(str[i]!==str[len-i-1]){ 
    return false
    }
 } 
return true
}