manacher能求出最大回文长度,并且时间复杂度为o(logn)。
实现该算法主要步骤:
1.构造p[ i ]值,记录每个字符回文数。
2.由于平时求回文得考虑奇偶情况,所以在字符间插入符号#(或其他没出现在字符串里的),这样就能将两种情况都转化成奇数的情况。(经典)
# a # b # a # b # a # b # c # a # b # d
P[i]: 1 2 1 3 1 6 1 6 1 4 1 2 1 2 1 2 1 2 1 1
观察知,当i=4时,p[ i ] = 3.问题:此时p[ i ] = 3是如何根据前面的p[ i ] 所推导得出的呢?
综合上述情况得出核心代码:
if(MaxId>i)
p[i]=Min(p[2*id-i],MaxId-i);
else
p[i]=1;
#include <stdio.h> char b[100020],a[200040]; int p[200040]; int Min(int a,int b) { return a<b?a:b; } int main() { int i,n,id,MaxL,MaxId; while(scanf("%s",&b[1])!=EOF) //输入时从b[1]地址开始存储字符串 { for(i=1;b[i]!='\0';i++) { a[(i<<1)]=b[i]; a[(i<<1)+1]='#'; } // 预处理 MaxL=MaxId=0; a[0]='?';a[1]='#'; n=(i<<1)+2;a[n]=0; //防止溢出 MaxId=MaxL=0; //maxid记录对称最大回文后一位值,maxl记录最大回文数 for(i=1;i<n;i++) { if(MaxId>i) //核心重点!!!! 画图更清晰 { p[i]=Min(p[2*id-i],MaxId-i); } else { p[i]=1; } while(a[i+p[i]]==a[i-p[i]]) //判断i的前后是否一致,p[i]为前后距离i的长度 { p[i]++; } if(p[i]+i>MaxId) //更新maxid的值,必须取最大区间 { MaxId=p[i]+i; id=i; //id记录最大回文的轴的i值 } if(p[i]>MaxL) { MaxL=p[i]; //maxl记录左边最大回文长度 } } printf("%d\n",MaxL-1); } return 0; }