力扣刷题日记19---剑指 Offer II 019. 最多删除一个字符得到回文
给定一个非空字符串 s,请判断如果 最多 从字符串中删除一个字符能否得到一个回文字符串。
示例 1:
输入: s = “aba”
输出: true
示例 2:
输入: s = “abca”
输出: true
解释: 可以删除 “c” 字符 或者 “b” 字符
示例 3:
输入: s = “abc”
输出: false
提示:
1 <= s.length <= 105
s 由小写英文字母组成
思路1:双指针 + 暴力
思路如下:首先判断 字符串s 是不是回文,如果是直接返回 true。否则,开始从头删除一个字符,判断剩下的字符串是不是回文,如果是直接返回 true;否则就删除第二个字符进行判断,删除第三个。。。
代码如下:
class Solution {
public:
bool validPalindrome(string s) {
int size = s.size();
string tmp = "";
string cur = "";
if (isPalindrome(s))
return true;
for (int i = 0; i < size; ++i) {
tmp = s;
cur = tmp.erase(i, 1);
if (isPalindrome(cur))
return true;
}
return false;
}
bool isPalindrome(string s){
int front = 0, end = s.size() - 1;
while(front < end){
if(s[front++] != s[end--])
return false;
}
return true;
}
};
时间复杂度:O(n2),isPalindrome() 的O(n) * validPalindrome() 的O(n),会超时;空间复杂度:O(n),字符串 tmp、cur 所占空间。
思路2:双指针 + 双指针
思路1是暴力循环判断删除一个字符后,剩余字符串是否满足回文。可以对这个思路进行优化,即使用双指针(一个指向头,一个指向尾),判断两个字符是否相等,相等就继续循环;不相等就:(1)删除 头指针字符 判断是否满足要求,(2)删除 尾指针字符 判断是否满足要求。只要两种情况中有一种满足要求就返回 true;若两种情况都不满足,返回false。
代码如下:
class Solution {
public:
bool validPalindrome(string s) {
int front = 0, end = s.size() - 1;
while(front < end){
if(s[front] != s[end]) //头尾指针所指字符不相等才进行判断
return isPalindrome(s, front + 1, end) || isPalindrome(s, front, end - 1);
front++;
end--;
}
return true;
}
bool isPalindrome(string s, int front, int end){
while(front < end){
if(s[front++] != s[end--])
return false;
}
return true;
}
};
时间复杂度:O(n);空间复杂度:O(1)。
还可以通过多写几行代码进一步减少所占用的内存。
代码如下:
class Solution {
public:
bool validPalindrome(string s) {
int front = 0, end = s.size() - 1;
bool b1 = true, b2 = true;
while(front < end){
if(s[front] != s[end]){
int left = front, right = end - 1;
while(left < right){
if(s[left++] != s[right--]){
b1 = false;
break;
}
}
left = front + 1, right = end;
while(left < right){
if(s[left++] != s[right--]){
b2 = false;
break;
}
}
break;
}
front++;
end--;
}
return b1 || b2;
}
};
时间复杂度:O(n);空间复杂度:O(1)。
思路3:双指针 + 递归
思路2中第一段代码中两个函数可以合并成一个函数,通过递归来实现。
代码如下:
class Solution {
public:
bool b = true;
bool validPalindrome(string s) {
int front = 0, end = s.size() - 1;
while(front < end && s[front] == s[end]){ //头尾指针所指字符相等才移动指针
front++;
end--;
}
if(front >= end) //说明不删除字符就满足回文要求
return true;
else if(b){ //只递归一次就行了,通过 b 进行判断
b = false;
return validPalindrome(s.substr(front,end - front)) || validPalindrome(s.substr(front + 1,end - front));
}
return false;
}
};
时间复杂度:O(n);空间复杂度:O(1)。