js_algorithm
js_algorithm copied to clipboard
验证回文字符串 Ⅱ
leetcode: https://leetcode-cn.com/problems/valid-palindrome-ii/
思路分析
这道题很多同学第一眼看过去,可能本能地会想到这样一种解法:若字符串本身不回文,则直接遍历整个字符串。遍历到哪个字符就删除哪个字符、同时对删除该字符后的字符串进行是否回文的判断,看看存不存在删掉某个字符后、字符串能够满足回文的这种情况。
这个思路真的实现起来的话,在判题系统眼里其实也是没啥毛病的。但是在面试官看来,就有点问题了——这不是一个高效的解法。
如何判断自己解决回文类问题的解法是否“高效”?其中一个很重要的标准,就是看你对回文字符串的对称特性
利用得是否彻底。
字符串题干中若有“回文”关键字,那么做题时脑海中一定要冒出两个关键字——对称性
和 双指针
。这两个工具一起上,足以解决大部分的回文字符串衍生问题。
回到这道题上来,我们首先是初始化两个指针,一个指向字符串头部,另一个指向尾部:
如果两个指针所指的字符恰好相等,那么这两个字符就符合了回文字符串对对称性的要求,跳过它们往下走即可。如果两个指针所指的字符串不等,比如这样:
那么就意味着不对称发生了,意味着这是一个可以“删掉试试看”的操作点。我们可以分别对左指针字符和右指针字符尝试进行“跳过”,看看区间在 [left+1, right]
或 [left, right-1]
的字符串是否回文。如果是的话,那么就意味着如果删掉被“跳过”那个字符,整个字符串都将回文:
比如说这里我们跳过了 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
};