好的讲解manacher算法的文章,图文并茂。
http://blog.csdn.net/ggggiqnypgjg/article/details/6645824
题解来源:http://blog.sina.com.cn/s/blog_6fa65cf90100s3sg.html
题意:求给定串的最长回文子串(2009多校题目)
分析:
枚举每个点向左向右扩展,看最远能扩展到哪儿.但是普通的枚举是n^2的,肯定超时。现在我们想kmp或扩展kmp一样,给字符串定义一个nex数组,nex[i]表示以i为中心最远能向右扩展的长度,使得s[i – nex[i] + 1……. i + nex[i]- 1]形成的回文。然后我们利用这个数组,在O(n)的时间内求出每个i的nex[i]。在其他算法中,奇数回文和偶数回文经常给我们带来麻烦,这个算法中,我们第一步要进行的是将每个字符后边(包括开头)加入一个字符(不在串儿的字符集中就行),一般用’#”. 这样就都转换为了奇数的情况。
例如 : abba (偶)
改为 #a#b#b#a# (最长为以第3个#为中心)
aba (奇)
改为 #a#b#a# (最长为以b为中心)
剩下的就是在我们知道了nex[0]…….nex[i – 1]后 如何求nex[i]; p记录前i-1个字符中以某个字符id为中心最远能向右扩展到的位置。
// File Name: 3068.cpp // Author: Zlbing // Created Time: 2013/5/9 13:30:20 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int maxn=2e5; char str[maxn],str1[maxn*2]; int n,ans,nxt[maxn*2]; void Manacher() { memset(nxt,0,sizeof(nxt)); int mx=0,id; for(int i=1;i<n;i++) { if(mx>i) nxt[i]=min(nxt[2*id-i],mx-i); else nxt[i]=1; for(;str1[i-nxt[i]]==str1[i+nxt[i]];nxt[i]++); if(i+nxt[i]>mx) { mx=i+nxt[i]; id=i; } } } void pre() { int i=0,k=1,t=0; str1[0]='$'; while(str[i]!='\0') { str1[k++]=t?str[i++]:'#'; t^=1; } str1[k++]='#'; str1[k]='\0'; n=k; } int main() { while(scanf("%s",str)==1) { pre(); Manacher(); int maxx=0; for(int i=0;i<n;i++) if(maxx<nxt[i]-1) maxx=nxt[i]-1; printf("%d\n",maxx); } return 0; }