kuangbin专题十六 KMP&&扩展KMP HDU3068 最长回文

给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等

Input输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000Output每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
Sample Input
aaaa

abab
Sample 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 }

猜你喜欢

转载自www.cnblogs.com/ACMerszl/p/10325382.html