在上篇《manacher算法处理最长的回文子串(一)》解释了manacher算法的原理,接着给该算法,该程序在leetcode的最长回文子串中通过。首先manacher算法维护3个变量。一个名为radius[i]的数组,表示以i为中心轴承的回文子串的半径,如abcdcba中,字符d的下标为4,则他的radius[4]=3,下标的为0的a的半径为radius[0]=0,即中心轴不考虑其中。一个idx表示上一次以idx为中心轴的回文。如果当以i为中心的回文在以idx为中心的回文内。则idx不更新,否则处理完radius[i]后,需要把idx更新为i。最后一个rad维护idx能够包含最大的范围的下一个字符下标,事实上当i+radius[i]到到达rad时就需要更新idx。
代码:
1 class Solution {
2 public:
3 string longestPalindrome(string s) {
4 int n=s.size();
5 string str(2*n+1,'0');
6 bool flag=1;
7 int j=0;
8 int maxIdx=0;
9 for(int i=0;i<2*n+1;i++){
10 if(flag){
11 str[i]='#';
12 flag=false;
13 }else{
14 str[i]=s[j++];
15 flag=true;
16 }
17 }
18 vector<int> radius(2*n+1,0);
19 int idx=0;
20 int rad=1;
21 for(int i=1;i<2*n+1;i++){
22 if(i>=rad){
23 forceExtend(str,radius,idx,rad,i);
24 maxIdx=(radius[i]>radius[maxIdx]?i:maxIdx);
25 }else if(i<rad){
26 int j=2*idx-i;
27 int idx_radius=idx-radius[idx];
28 int j_radius=j-radius[j];
29 if(j_radius>idx_radius){
30 radius[i]=radius[j];
31 }
32 else if(j_radius<idx_radius){
33 radius[i]=idx+radius[idx]-i;
34 }else{
35 radius[i]=idx+radius[idx]-i;
36 int count=1;
37 while((i+radius[i]+count)<=str.size()&&(i-radius[i]-count)>=0&&str[i+radius[i]+count]==str[i-radius[i]-count])
38 count++;
39 radius[i]+=(count-1);
40 if(i+radius[i]>=rad){
41 idx=i;
42 rad=i+count;
43 }
44 }
45 maxIdx=(radius[i]>radius[maxIdx]?i:maxIdx);
46 }
47
48 }
49 string ret=getMaxSubString(str,maxIdx,radius[maxIdx]);
50 return ret;
51 }
52 void forceExtend(const string& str, vector<int>& radius,int &idx,int &rad,const int k){
53 int count=1;
54 while((k-count)>=0&&(k+count)<str.size()&&str[k-count]==str[k+count]){
55 count++;
56 }
57 radius[k]=count-1;
58 if(k+radius[k]>=rad){
59 idx=k;
60 rad=k+count;
61 }
62 }
63 string getMaxSubString(const string &str,const int k,const int r){
64 string ret(r,'0');
65 int j=0;
66 for(int i=k-r+1;i<=k+r;i+=2){
67 ret[j++]=str[i];
68 }
69 return ret;
70 }
71
72 };