最短回文串
给定一个字符串 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;
}
};