b | a | a | a |
---|
将字符串s扩展为:
$ | # | b | # | a | # | a | # | a | # | ^ |
---|
前后加的特殊字符是为了避免去判断边界的条件,算法维护两个域:id:表示能到达最右边的回文的中心,mx表示能到达最右的边界。
其次还需要一个数组v记录下以i为中心的回文长度(的一半)。
然后我们从左往右遍历新生成字符串,更新mx和id,对于某一位置i,设j=2*id-i,j为i相对于id的对称位置,当v[j]+i>mx时,v[i]=mx-i;
当v[j]+i
class Solution {
public:
string longestPalindrome(string s) {
int size=s.size();
if(size<=1)return s;
int n=2*size+3;
string str(2*size+3,'#');
for(int i=0;i<size;i++){
str[2*(i+1)]=s[i];
}
str[0]='$';
str[n-1]='^';
vector<int> v(n,0);
int mx=0,id=0;//core of the index
for(int i=0;i<n;i++){
if(mx>i){
if(v[2*id-i]+i>mx){
v[i]=mx-i;
}
else if(v[2*id-i]+i<=mx){
v[i]=v[2*id-i];
}
}
else v[i]=0;
while(str[i+v[i]+1]==str[i-v[i]-1])v[i]++;
if(v[i]>v[id]){
id=i;
mx=i+v[id];
}
}
for(int i=0;i<n;i++){
// cout<<i<<":"<<v[i]<<" ";
}
cout<<endl;
return s.substr((id-v[id])/2,v[id]);
}
};
$ | # | b | # | a | # | a | # | a | # | ^ |
---|
看下面两个例子:
$ | # | b | # | a | # | a | # | a | # | ^ |
---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 2 | 1 | 2 | 3 | 4 | 3 | 2 | 1 | 1 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
本例中id为位6,mx为4,对应原来字符串s中的位置为:(6-(4-1))/2=>1,长度为mx-1 =>3
我们从原串s中的取得substr(1,3)就是它的最长子串。
$ | # | b | # | a | # | a | # | ^ |
---|---|---|---|---|---|---|---|---|
1 | 1 | 2 | 1 | 2 | 3 | 2 | 1 | 1 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
本例中id为位5,mx为3,对应原来字符串s中的位置为:(5-(3-1))/2=>1,长度为mx-1 =>2。
我们从原串s中的取得substr(1,2)就是它的最长子串。