https://leetcode-cn.com/problems/shortest-palindrome/
思路:思路其实很简单,因为只能在字符串的头部添加字符,所以我们只要找到下标从0开始的最长回文串
s
1
s_1
s1,假设后面部分为
s
2
s_2
s2,那么答案就等于
r
e
v
e
r
s
e
(
s
2
)
+
s
reverse(s_2)+s
reverse(s2)+s。怎么在线性复杂度内找到
s
1
s_1
s1呢?我们有两种方法,第一种方法是利用
h
a
s
h
hash
hash,通过定义进制数和模数,我们可以将一个字符串表示成数字,比如进制为
10
10
10,模数为
100
100
100时,
h
a
s
h
(
b
c
d
)
=
(
100
∗
1
+
10
∗
2
+
1
∗
3
)
%
100
=
23
hash(bcd)=(100*1+10*2+1*3)\%100=23
hash(bcd)=(100∗1+10∗2+1∗3)%100=23。再考虑回文串的性质:如果
s
s
s是一个回文串,且
t
=
r
e
v
e
r
s
e
(
s
)
t=reverse(s)
t=reverse(s),那么有
t
=
s
t=s
t=s。那么自然有
h
a
s
h
(
t
)
=
h
a
s
h
(
s
)
hash(t)=hash(s)
hash(t)=hash(s),这样我们就可以在
O
(
n
)
O(n)
O(n)内求出最长的回文串
s
1
s_1
s1啦,但是哈希是有可能发生碰撞的,也就是说两个不相等的字符串的哈希值一样,为了避免这种情况,我们一般使用一个质数作为进制数,同时选取另一个大质数作为模数。下面给出方法一的代码:
class Solution {
public:
using ll=long long;
string shortestPalindrome(string s) {
int siz=s.size();
int base=131,mod=1e9+7;
int idx;
ll hash1=0,hash2=0,rightbs=1;
for(int i=0;i<siz;i++){
hash1=(hash1*base+s[i]-'a')%mod;
hash2=(hash2+rightbs*(s[i]-'a'))%mod;
rightbs=(rightbs*base)%mod;
if(hash1==hash2)
idx=i;//说明[0,idx]构成一个回文串
}
//得到最大的idx 开始拼接
string tmp=siz?s.substr(idx+1,siz-idx-1):"";
reverse(tmp.begin(),tmp.end());
return tmp+s;
}
};
方法二需要用到 K M P KMP KMP算法。我们假设 t = r e v e r s e ( s ) t=reverse(s) t=reverse(s),把 s s s作为模式串, t t t作为查询串,当遍历到 t t t的末尾时,易得模式串指针 j j j的值,也就是说 s [ 0 … j ] = t [ n − j − 1 , n − 1 ] s[0…j]=t[n-j-1,n-1] s[0…j]=t[n−j−1,n−1],由于 t = r e v e r s e ( s ) t=reverse(s) t=reverse(s),所以可以得到 s [ 0 … j ] = s [ j … 0 ] s[0…j]=s[j…0] s[0…j]=s[j…0],也就是说 s [ 0 … j ] s[0…j] s[0…j]是下标从 0 0 0开始的最长的回文串,那么问题就解决辣。
class Solution {
public:
using ll=long long;
string shortestPalindrome(string s) {
int siz=s.size();
if(!siz)
return s;
vector<int> next(siz);
int k=-1,i=0,j=0;
next[0]=-1;
while(i<siz-1){ //kmp--求next数组
if(k==-1||s[i]==s[k]){
if(s[++i]==s[++k])
next[i]=next[k]; //优化
else
next[i]=k;
}
else
k=next[k];
}
i=siz-1;//reverse(s)作为查询串 所以i要逆序扫
while(i>=0){
if(j==-1||s[i]==s[j])
--i,++j;
else
j=next[j];
}
string tmp=s.substr(j,siz-j);
reverse(tmp.begin(),tmp.end());
return tmp+s;
}
};