kuangbin专题十六 KMP&&扩展KMP HDU3068 最长回文
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
回文就是正反读都是一样的字符串,如aba, abba等
Input输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000Output每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
Sample Input
aaaa ababSample Output
4 3
马拉车裸题。
再次学习马拉车
第一步:字符串预处理,保证长度都为奇数。
明确id,mx的含义 id为最远回文对应的中心位置,mx为最远回文位置
用p[i]记录以i为中心的最大回文半径
第二步:求p[i]
分两种情况:
一、mx > i
①,mx-i>p[i]
如图所示:红色部分为i的回文范围。i和j关于id对称。说明p[i]=p[j]=p[2*id-i]
②,mx-i<=p[i]
如图所示,红色为中心为i的回文范围,如果i+p[i]>mx, 那么只能说明 mx-i 这一段是可以由之前的推出来的
因为 mx是以id为中心,对应最远的回文右边界。所以这种情况p[i]=mx-i
二、mx<=i
说明根本不知道以后的情况,只能p[i] = 1
1 #include<stdio.h> 2 #include<algorithm> 3 #include<string.h> 4 using namespace std; 5 char s[110010],snew[220010]; 6 int p[220010]; 7 8 int manacher(char* s) { 9 int l=0; 10 snew[l++]='$'; 11 snew[l++]='#'; 12 for(int i=0;s[i];i++) { 13 snew[l++]=s[i]; 14 snew[l++]='#'; 15 } 16 snew[l]='\0'; 17 int id=0,mx=0,maxlen=-1; 18 for(int i=0;i<l;i++) { 19 p[i]=i<mx?min(p[2*id-i],mx-i):1; 20 while(snew[i+p[i]]==snew[i-p[i]]) p[i]++; 21 if(i+p[i]>mx) { 22 mx=i+p[i]; 23 id=i; 24 } 25 if(p[i]>maxlen) maxlen=p[i]-1; 26 } 27 return maxlen; 28 } 29 30 int main() { 31 while(~scanf("%s",s)) { 32 printf("%d\n",manacher(s)); 33 } 34 return 0; 35 }