【问题】
给定一个字符串,问对该字符串,是否能通过添加一个字符后变为回文串。
若可以,输出 YES,否则输出 NO
对于该问题,首先要明白,删除一个字符与添加一个字符在判断回文串中是等价的。
【暴力枚举】
先判断字符串是否回文,若是回文,可以在中间添加/删除一个字符(对于奇数串,添加/删除中间的那个字符;对于偶数串,可在中间添加任意一个字符,可删除中间两个任意一个字符),直接返回 YES,若字符串不是回文,依次去掉一个字符后判断剩下的字符串是否为回文串
例如:对于字符串 abcddecba,首先去掉 a,判断 bcddecba,然后去掉 b,判断 acddecba,再去掉 c,判断 abddecba,以此类推的进行下去,若发现回文即可停止返回 YES,反之如果一直没发现回文串,返回 NO
时间复杂度:O(n^2)
bool isPalindrome(string str){//判断字符串是否为回文
string temp=str;
reverse(temp.begin(),temp.end());//反转字符串
return str==temp;//比较与原字符串是否相同
}
int main(){
string str;
cin>>str;
int len=str.size();//字符串长度
bool flag=false;
for(int i=0;i<str.size();i++){//从第一个字符开始枚举
if(isPalindrome(str.substr(0,i)+str.substr(i+1,str.size()-1-i))){
flag=true;
break;
}
}
if(flag)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
return 0;
}
【翻转解法】
该方法可以解决一类问题:对原字符串添加/删除几个字符可以构成回文串
先将原字符串逆序,然后计算两字符串的最长公共子序列长度,设 diff 为若可形成回文串,原字符串要添加/删除的个数,故有:diff=字符串长度-最长公共子序列长度
对于该问题,只要判断 diff<=1 即可
时间复杂度:O(N^2)
int LCS(string str,string rstr) {
if(str.size()==0 || rstr.size()==0)//字符串长度为0
return 0;
vector< vector<int> > dp(str.size()+1,vector<int>(rstr.size()+1,0));
for(size_t i=1; i<= str.size(); ++i){//原字符串的长度
for(size_t j=1; j<= rstr.size(); ++j){//反转字符串的长度
if(str[i-1] == rstr[j-1])//前面填充了一行一列,因此判断i-1和j-1
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
return dp[str.size()][rstr.size()];
}
int main(){
//原字符串
string str;
cin>>str;
//反转字符串
string rstr=str;
reverse(rstr.begin(),rstr.end());
int diff=str.size()-LCS(str,rstr);
if(diff<=1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
return 0;
}
【掐头去尾】
首先找到字符串不匹配的位置,然后提取出中间不匹配的字符串,分别判断其去掉头和去掉尾后的两个字符串是否为回文,若其中一个为回文,返回 YES 即可。
例如:abcddecba,取出 dde,分别判断 dd 和 de,发现其中有一个满足回文,即返回 YES,否则返回 NO
时间复杂度:O(n^2)
bool isPalindrome(string str){//判断是否为回文
for(int i=0;i<str.size()/2;i++)
if(str[i]!=str[str.size()-1-i])
return false;
return true;
}
int main(){
string str;
cin>>str;
int pos=str.size()/2;
for(int i=0;i<str.size()/2;i++){
if(str[i]!=str[str.size()-1-i]){
pos=i;//记录不匹配的位置
break;
}
}
bool flag=false;
if(pos==str.size()/2)//不匹配位置在中间
flag=true;
else{
bool str1=isPalindrome(str.substr(pos+1,str.size()-2*pos-1));//掐头
bool str2=isPalindrome(str.substr(pos,str.size()-2*pos-1));//去尾
flag=(str1||str2);//一个为true即为true
}
if(flag)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
return 0;
}