标签:说明 char ret algo for mil 偶数 i++ style
Manacher是用来求最长回文子串的。做法很好理解,有一点贪心的感觉。
解释一下加#号
字符串abbaba,abba和aba都回文子串,但是一个长度是奇数,一个是偶数,直接做还要分情况讨论。如果变成#a#b#b#a#b#a#,那#a#b#b#a#和#a#b#a# 长度都是奇数,而且开头结尾都是#号,这样比较方便。
具体的做法结合代码、注释就可以理解了
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int p[210000],L[210000],R[210000]; //p[i]表示以i为中心所形成的回文串的i~R的长度 //L(R)[i]代表以i为中心所形成的最长回文子串的最左(右)点 //显然p[i]=R[i]-i+1或i-L[i]+1 char s[210000],now[210000];//now表示加了#号形成的新字符串 int main() { while(scanf("%s",s+1)!=EOF) { int len=strlen(s+1);//字符之间的间隙加上#号,两种情况:abba和aba就合为一种了 for(int i=1;i<=len;i++){now[2*i-1]=‘#‘;now[2*i]=s[i];} len=len*2+1;now[len]=‘#‘; int k=0;//k表示目前能到达最远点的回文串的中心(R最大) L[k]=0;R[k]=0; for(int i=1;i<=len;i++) { int j=k-(i-k);//j为i关于k的对称点 if(i<=R[k])p[i]=min(p[j],j-L[k]+1);//i在以k为中心的回文串里 //L[k]~j~k~i~R[k] //如果L[k]<L[j],那说明j整个回文串都在k里,那i就和j一样 //否则就只能确定从L[k]~j是可以回文的 else p[i]=1;//不然就要暴力枚举 while(1<=i-p[i]&&i+p[i]<=len&&now[i-p[i]]==now[i+p[i]])p[i]++;//向左右枚举,更新p[i] L[i]=i-p[i]+1;R[i]=i+p[i]-1; if(R[i]>R[k])k=i; } int ans=0; for(int i=1;i<=len;i++)ans=max(ans,p[i]-1); printf("%d\n",ans); /* 当前的最长回文子串长度为2*p[i]-1 因为#号处于首尾和每个字符之间,所以我们就可以保证所得出的最长回文子串的首尾都为# 这时我们可以得出不带#号的回文串的长度为(2*p[i]-1-1)/2=p[i]-1 所以真正的最长回文子串就是p[i]-1 */ } return 0; }
标签:说明 char ret algo for mil 偶数 i++ style
原文地址:http://www.cnblogs.com/AKCqhzdy/p/7536086.html