最短回文串

Posted 929code

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短回文串相关的知识,希望对你有一定的参考价值。

给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。

1. 暴力法

实际上是求以第一个字符为开头的最长回文子串

class Solution 
public:
    string shortestPalindrome(string s) 
        int len = 0;
        int n = s.size();
        if(n<2) return s; 
        for(int i=0;i<n;i++)
            if(help(s,i)) len = i;
        string res = s.substr(len+1);
        reverse(res.begin(),res.end());
        return res + s;
    
    bool help(string&s,int end)
        int i = 0;
        while(i<end)
            if(s[i]!=s[end]) return false;
            i++;
            end--;
        
        return true;
    
;

2. 特殊编码(不稳定)

设计一种编码方式使得,正序与反序计算出来的数值一样,这样就可以利用前面的计算结果
但会存在误判(必然存在不是回文的串,正序反序计算数值一样),把非回文串判成回文串

class Solution 
public:
    string shortestPalindrome(string s) 
        int n = s.size();
        int base = 2;//用于编码的基底,可以取任意数
        int mod = 1000000007;//防止编码时数值过大
        int left = 0, right = 0, mul = 1;
        int best = -1;//最远回文串结束位置
        for (int i = 0; i < n; ++i) 
            left = ((long long)left * base + s[i]) % mod;
            right = (right + (long long)mul * s[i]) % mod;
            if (left == right) best = i;//编码相同
            mul = (long long)mul * base % mod;//当前基底进制
        
        string add =  s.substr(best + 1);
        reverse(add.begin(), add.end());
        return add + s;
    
;

3. KMP算法

将串当做模板串,去匹配翻转后的串,失效后不用重头开始,跑完匹配串后,得到最远距离
fail[i]表示s[i]在前缀中相等的最远距离,没有相等值用-1表示
每次先进行转移,查看fail[i-1],然后比较其后一个元素,与当前主串元素是否相等,实现动态规划

class Solution 
public:
    string shortestPalindrome(string s) 
        int n = s.size();
        //PM表建立遵循先减后增的规律,即先参考上一个位置的PM值,即减
        //然后跳转到对应PM值的下一位置,进行比较,进行计算
        vector<int> fail(n, -1);//初始无前一元素,跳转-1,同时表示无相等元素,因为后面还要增
        for (int i = 1; i < n; i++)//从1开始,评估每个位置应跳转的地方
            int j = fail[i - 1];//前一元素的跳转位置
            while (j != -1 && s[j + 1] != s[i]) //跳转后的后一元素继续比较当前元素
                j = fail[j];//,匹配失效,继续跳转,压缩转移位置
            if (s[i] == s[j + 1])   fail[i] = j + 1;//相等记录该位置
        
        int best = -1;//回文串最远位置
        for (int i = n - 1; i >= 0; --i) 
            while (best != -1 && s[best + 1] != s[i]) 
                best = fail[best];
            if (s[best + 1] == s[i]) best++;
        
        string add = s.substr(best + 1);
        reverse(add.begin(), add.end());
        return add + s;
    
;

添加回文串

题目描述

对于一个字符串,我们想通过添加字符的方式使得新的字符串整体变成回文串,但是只能在原串的结尾添加字符,请返回在结尾添加的最短字符串。

给定原字符串A及它的长度n,请返回添加的字符串。保证原串不是回文串。

测试样例:
"ab",2
返回:"a"
 
问题分解
1、找到最长的回文子串
2、剩余部分就是需要添加的子串
 
使用Naive查找,寻找最大公共串
这里用到了:翻转子串==原子串 =>回文子串
从原串的开头开始找,比较是否与翻转串的末尾相同
【这里用到了本题的特征:已有的回文子串肯定出现在末尾,不会出现在中间】
 
string addToPalindrome(string A, int n) {
        string s = A;
        reverse(s.begin(),s.end()); // 取得翻转串
        for(int i=0;i<n;i++) // Naive查找
             if(A.substr(i,n-i)==s.substr(0,n-i))//求最长公共子串
                return s.substr(n-i,i);//返回公共集后面剩余字符串
        return string("");
    }

  

//每次删除掉第一个字符,将这个删除掉的字符放入一个新串中
//如果删除后的字符串是回文串则返回,否则继续第一步
//逆序ans返回
class Palindrome {
    bool judge(string str){
        string tmp = str;
        reverse(tmp.begin(), tmp.end());
        return tmp==str;
    }
public:
    string addToPalindrome(string str, int n) {
        reverse(str.begin(), str.end());
        string ans;
        while (!str.empty()) {
            ans.push_back(str.back());
            str.pop_back();
            if(judge(str))
                break;
        }
        reverse(ans.begin(), ans.end());
        return ans;
    }
};

  

以上是关于最短回文串的主要内容,如果未能解决你的问题,请参考以下文章

添加回文串

LeetCode﹝回文ி﹞数串链表对

LeetCode﹝回文ி﹞数串链表对

LeetCode﹝回文ி﹞数串链表对

LeetCode﹝回文ி﹞数串链表对

最长(大)回文串的查找(字符串中找出最长的回文串)PHP实现