题目描述
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: "aba"
输出: True
示例 2:
输入: "abca"
输出: True
解释: 你可以删除c字符。
注意:
字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
题解思路
我们先来看看最简单的情况,也就是不删除字符的情况,然后再递进看看删除情况。
- 不删除字符的情况
先考虑如果不允许删除字符,如何判断一个字符串是否是回文串?双指针!!!
定义左右指针left、right,初始时分别指向字符串的第一个字符和最后一个字符。
每次判断左右指针指向的字符是否相同,如果不相同,则不是回文串;如果相同,则将左右指针都往中间移动一位,直到左右指针相遇,则字符串是回文串。
- 删除1个字符的情况
在前面不删除的情况下,发现在找到不相等的元素时,[0, left) 和 (right, len(s) - 1] 这两部分已经判断过是回文,因此不用再次判断。
剩下的只需要再判断 [left, right] 区间中的字符串,即删除 left 或者 right 指向的元素,剩余的区间 (left, right] 或者 [left, right) 是否为回文串。
若 (left, right] 或者 [left, right) 为回文串,则说明删除了一个字符可以构成回文串。
注意的是:若删除过一次,则不是回文串。
如果左右指针从两端同时向中间走,那么:
第一步:
a b c a
| |
left right
第二步:
a b c a
| |
left right
第一步,左右指针遇到的元素相等,继续向中间走;
第二步,左右指针遇到的元素不等,则必须进行处理:我们必须删除其中的一个字符,然后再判断 剩余的所有字符 是否是回文串。
删除 b:
a c a
或者
删除 c:
a b a
即判断 aca 或者 aba 是否为回文字符串。
看看官方给出的实例,辅助理解:
代码
class Solution {
int del = 0; // 记录删除节点的次数
public boolean validPalindrome(String s) {
int left = 0, right = s.length()-1; // left左指针 right右指针
while(left < right){
if(s.charAt(left) == s.charAt(right)){
left++;
right--;
}else{
// 不相等的话,若没有删除字符,则删除左边或右边的字符再判断
// 若删除过一次,则不是回文串
if(del == 0){
del++;
return validPalindrome(s.substring(left, right)) || validPalindrome(s.substring(left+1, right+1));
}
return false;
}
}
return true;
/* if(left > right) return true; */
}
}
复杂度分析
时间复杂度:O(n)。其中 n 是字符串的长度。判断整个字符串是否是回文字符串的时间复杂度是 O(n),遇到不同字符时,判断两个子串是否是回文字符串的时间复杂度也都是 O(n)。
空间复杂度:O(1)。只需要维护有限的常量空间。