最短回文串
题意:求最长回文前缀。
- 字符串hash
求出字符串hash之后倒序遍历即可。
#define ull unsigned long long
class Solution {
public:
static const int P = 1e9+7;
vector<ull> h1,h2,p{
1};
string shortestPalindrome(string s) {
int n = s.size(), len = 0;
h1.resize(n+10),h2.resize(n+10),p.resize(n+10);
for(int i=1;i<=n;i++){
p[i] = p[i-1]*P;
h1[i] = h1[i-1]*P+(s[i-1]-'A'+1);
}
for(int i=n;i>=1;i--) h2[i] = h2[i+1]*P+(s[i-1]-'A'+1);
for(int i=n;i>=1;i--){
if( h1[i] == h2[1]-h2[ i+1]*p[i] ){
len = i;
break;
}
}
string t = s.substr(len,n-len);
reverse(t.begin(),t.end());
return t+s;
}
};
- KMP
将原来的串作为pattern串,它的逆转作为text串。
然后求出文本串以最后一个字符结尾的串能和pattern串的前缀匹配的长度。
这就是一开始那个串的最长回文前缀。
class Solution {
public:
vector<int> next;
string shortestPalindrome(string s) {
string p = s;
reverse(s.begin(),s.end());
int n = s.size(), j = 0, len = 0;
next.resize(n+2,0);
for(int i=2;i<=n;i++){
while(j>0 && p[i-1]!=p[j]){
j = next[j];
}
if(p[i-1]==p[j]){
j++;
}
next[i] = j;
}
j = 0;
for(int i=1;i<=n;i++){
while(j>0 && (j==n || s[i-1]!=p[j])){
j = next[j];
}
if(s[i-1]==p[j]){
j++;
}
}
len = j;
string t = s.substr(0,n-len);
return t+p;
}
};
一个更加巧妙的做法,直接把字符串的逆转加到原始串的后面,中间加上分割符,跑出next数组。然后最长公共前后缀就是我们要求的最长回文前缀。
class Solution {
public:
vector<int> next;
string shortestPalindrome(string s) {
string p = s;
reverse(s.begin(),s.end());
s = p+"#"+s;
int n = s.size(), j = 0, len = 0;
next.resize(n+2,0);
for(int i=2;i<=n;i++){
while(j>0 && s[i-1]!=s[j]){
j = next[j];
}
if(s[i-1]==s[j]){
j++;
}
next[i] = j;
}
len = j;
string t = s.substr(p.size()+1,p.size()-len);
return t+p;
}
};