问题描述
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: “aba”
输出: True
示例 2:
输入: “abca”
输出: True
解释: 你可以删除c字符。
注意:
字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
初始思路
设置两个指针分别指向字符串的开头和结尾,每次比较开头结尾的两个字符,如果相同则前面指针后移,后面指针前移,继续进行比较;如果遇到不同的情况,若满足最多删除一个字符就是回文字符串那么这两个字符必然会删除一个,记录第一次出现不同的左右指针位置,接下来判断前指针后移和后指针指向的字符是否相同,或后指针前移和前指针指向的字符是否相同,如果是第一种情况下又出现字符不同的情况就将前后指针还原,若第二种情况下又出现字符不同的情况直接返回false。当左右指针相遇返回true。
初始代码
class Solution {
public boolean validPalindrome(String s) {
int right=s.length()-1;
int left=0;
int count=0;//记录冲突次数
int firstLeft=-1;//第一次冲突的做指针
int firstRight=-1;//第一次冲突的右指针
while(right>left){
if(s.charAt(left)!=s.charAt(right)){
if(count==2)return false;
count++;
firstLeft=(firstLeft==-1)?left:firstLeft;
firstRight=(firstRight==-1)?right:firstRight;
if(s.charAt(left+1)==s.charAt(right)&&count<2){
left++;
}else if(s.charAt(right-1)==s.charAt(left)&&count<2){
right--;
}else{
left=firstLeft-1;
right=firstRight;
}
}
left++;
right--;
}
return true;
}
}
初始结果
执行时间 | 8ms | 89.65 |
---|---|---|
消耗内存 | 40.4M | 6.67 |
优化思路
这次我们换一种思路,如果最多删除一个字符就是回文字符串,那么假设发生冲突时的左右指针为i,j,那么从i+1到j的字符串和从i到j-1的字符串至少有一个为回文字符串,因此可以使用递归实现。
优化代码
class Solution {
public boolean validPalindrome(String s) {
return isValid(s,0,s.length()-1,false);
}
public boolean isValid(String s,int i,int j,boolean hasBack){
while(i<j){
if(s.charAt(i)!=s.charAt(j)){
if(hasBack)return false;
return isValid(s,i+1,j,true) ||isValid(s,i,j-1,true);
}
i++;
j--;
}
return true;
}
}
优化结果
执行时间 | 6ms | 99.84 |
---|---|---|
消耗内存 | 40.3 | 6.67 |
总结
要学会如何定位到问题的本质和如何精简代码。