题目
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: "aba"
输出: True
示例 2:
输入: "abca"
输出: True
解释: 你可以删除c字符。
注意:
字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
思路
先按照正常判断回文串的方法,左右双指针相向而行,当遇到错误(左右两个指针的字符不同)的时候,先尝试删除左边的字符,判断剩余的子串是否是回文串,如果不行再尝试删除右边的,都不行就返回 false。
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
C++ 代码
class Solution {
public:
bool validPalindrome(string s) {
int left = 0, right = s.size() - 1;
while (left <= right) {
if (s[left] != s[right]) {
bool error = false;
// 先尝试删除左边的字符
int tempLeft = left;
++left;
while (left <= right) {
if (s[left++] != s[right--]) {
error = true;
break;
}
}
if (!error)
return true;
// 复原left和right,尝试删除右边的字符
left = tempLeft;
right = s.size() - left - 1;
--right;
while (left <= right) {
if (s[left++] != s[right--])
return false;
}
return true;
}
++left;
--right;
}
return true;
}
};
改进版
看了题解之后发现可以把判断子串是否是回文串拉出来写成一个函数,写法简洁很多。
class Solution {
public:
// 判断字符串s的子串[start, end]是不是回文字符串
bool validPalindrome(string& s, int start, int end) {
while (start <= end) {
if (s[start++] != s[end--])
return false;
}
return true;
}
bool validPalindrome(string s) {
int left = 0, right = s.size() - 1;
while (left <= right) {
if (s[left] != s[right]) {
bool error = false;
// 先尝试删除左边的字符
if (validPalindrome(s, left + 1, right))
return true;
// 尝试删除右边的字符
return validPalindrome(s, left, right - 1);
}
++left;
--right;
}
return true;
}
};