一、题目描述
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: "aba" 输出: True
示例 2:
输入: "abca" 输出: True 解释: 你可以删除c字符。
注意: 字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
二、思路分析
注意读题,非空字符串最多删除一个字符,判断是否能成为回文字符串。那应该存在两种情况,其自身就是回文字符串,或者去掉一位后是一个回文字符串。那第一步我们要解决的肯定是判断字符串是否回文。
1.判断字符串回文
这个问题有点眼熟,不就是前两天我写过的验证回文字符串 一的题解吗
在这里首先想到的应该是字符串反转与自身比较是否相等,因为js字符串不支持直接反转,所以需要将字符串转化为数组,反转后再转化为字符串与自身比较,直接上代码
const isPalindrome = str => str.split('').reverse().join('') === str
另一种方法当然是使用双指针,使用头尾两个指针比较字符串字符是否相等,相等则两个指针相向移动,直到两个指针相遇或相邻则停止。
const isPalindrome = str => Array
.from({length: str.split('').length >> 1})
.every((v, i) => str[i] === str[str.length - i - 1])
2.去除每一位字符验证
开始我的思路是循环字符串,将每一位字符从字符串移除后判断剩下的字符串是否为回文,直接上代码
var validPalindrome = function (s) {
const isPalindrome = str => str.split('').reverse().join('') === str
if (isPalindrome(s)) return true
let sArr = s.split('')
return Array.from({length: s.length}).some((v, i) =>
isPalindrome(sArr.filter((v, inx) => inx !== i).join(''))
)
};
时间复杂度O(n^2)果不其然超时了,继续优化。
3.去掉一位就能达到回文的条件
换一种思路可能会发现问题比预想的要更简单。先来想想我们用双指针是如何判断字符串回文的:两个指针位于字符串首尾字符,判断两个字符是否相等,如果相等那么两个指针相向移动,再次判断,直到指针相遇。
本题的最多删除一个字符后字符串是否回文,可以理解为判断字符串回文且有一次容错的机会,当遇到首位指针移动且不相等时,跳过这次判断继续执行(这里有删除左边指针和删除右边指针两种情况,这里直接校验左指针右移和右指针左移两种情况),如果再遇到不相等,之后的判断就和二分法判断字符是否相等完全一致了。
var validPalindrome = function (s) {
const isPalindrome = str => Array
.from({length: str.split('').length >> 1})
.every((v, i) => str[i] === str[str.length - i - 1])
for (let i = 0; i < s.length >> 1; i++) {
if (s[i] !== s[s.length - i - 1]) {
if (s[i] === s[s.length - i - 2] || s[i + 1] === s[s.length - i - 1]) {
return isPalindrome(s.split('').filter((v, index) => index >= i && index < (s.length - i - 1)).join(''))
|| isPalindrome(s.split('').filter((v, index) => index > i && index <= (s.length - i - 1)).join(''))
} else {
return false
}
}
}
return true
}
END
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情