manacher找出最长回文串

熟悉算法的可能知道manacher在线性时间能够找出最长回文串长度,但是要想找出最长回文串是谁,需要做一些改进,这时需要分奇偶讨论,枚举中心点。该题目来源于LeetCode 第五题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class  {
public:
string longestPalindrome(string s) {

if(s=="") return "";

int idl=0, idr=0, anslen=0;
int *r=new int[s.length()+5];

memset(r, 0, sizeof r);

int mx=0, mid=0;

for(int i=0; i<s.length(); i++){
r[i]=i<mx ? min(r[2*mid-i], mx-i) : 1;

while(i-r[i]>=0 && i+r[i]<=s.length() && s[i-r[i]]==s[i+r[i]]){
r[i]++;
}
if(i+r[i]>mx){
mid=i;
mx=i+r[i];
}

if(anslen<2*r[i]-1){
anslen=2*r[i]-1;
idl=i-r[i]+1; idr=i+r[i]-1;
}
}

memset(r, 0, sizeof r);

mx=0, mid=0;
//even
for(int i=0; i<s.length()-1; i++){
r[i]=i<mx? min(r[2*mid-i], mx-i) : 0;

while(i-r[i]>=0 && i+r[i]+1<s.length() && s[i-r[i]]==s[i+r[i]+1]) r[i]++;

if(i+r[i]>mx){
mid=i;
mx=i+r[i];
}

if(anslen<2*r[i]){
anslen=2*r[i];
idl=i-r[i]+1; idr=i+r[i];
}
}

string ans=s.substr(idl, anslen);

return ans;
}
};

传统的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
char Ma[MAXN*2];
int Mp[MAXN*2];
void MAnacher(char s[], int len){
int l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0; i<len; i++){
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;
int mx=0, id=0;
for(int i=0; i<l; i++){
Mp[i]=mx>i?min(Mp[2*id-i], mx-i):1;
while(Ma[i+Mp[i]]==Ma[i-Mp[i]]) Mp[i]++;
if(i+Mp[i]>mx){
mx=i+Mp[i];
id=i;
}
}
//Mp[]中的最大值就是最长回文串的长度
}