添加/删除字符后是否为回文串

【问题】

给定一个字符串,问对该字符串,是否能通过添加一个字符后变为回文串。

若可以,输出 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 即可。

扫描二维码关注公众号,回复: 5578330 查看本文章

例如:abcddecba,取出 dde,分别判断 dd 和 de,发现其中有一个满足回文,即返回 YES,否则返回 NO

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;
}

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/88579893