PS:做了个模板题就以为会Manacher了,结果昨天比赛遇到一个Manacher的题,还是没做出来。我就是眼高手低,浅尝辄止的一sb。
r[i]:是以i为中心的最长回文串的半径,因为有填充字符,所以,r[i]-1还是回文串的长度,在原串的起始位置是中间位置减去半径再除以2,即 (i-r[i])/2。
给出一个只由小写英文字符a,b,c…y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c…y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
Sample Input
aaaa
abab
Sample Output
4
3
推荐一个大牛博客:https://www.cnblogs.com/grandyang/p/4475985.html
马拉车算法,详情请看代码注释。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#define LL long long
#define PI acos(-1.0)
const int maxn=2e6+100;
const int inf=0x3f3f3f3f;
using namespace std;
char s[maxn],ss[maxn];
int r[maxn];
int Manacher(int n)
{
int cnt=0;
ss[cnt++]='$';
ss[cnt++]='#';
for(int i=0;i<n;i++)
{
ss[cnt++]=s[i];
ss[cnt++]='#';
}
ss[cnt++]='/0';
int pos=0,rx=0,ans=1;
//pos:目前回文子串能到最右位置所对应的中心
//rx:目前回文子串能到的最右位置
for(int i=1;i<cnt;i++)
{
r[i]=rx>i?min(r[2*pos-i],rx-i):1;
//这里设j是i以pos为对称轴时所对应的位置,那么i+j=2*pos。
//所以,当r[2*pos-i]<rx-i时,r[i]==r[2*pos-i]。
while(ss[i-r[i]]==ss[i+r[i]]) r[i]++;
//rx之后的要一个个试。
if(rx<i+r[i])
{
rx=i+r[i];
pos=i;
}
if(ans<r[i]-1)
ans=r[i]-1;
//ans=max(ans,r[i]-1); 迷之超时。
}
return ans;
}
int main(void)
{
int flag=0;
while(~scanf("%s",s))
{
if(flag) getchar();
else flag=1;
printf("%d
",Manacher(strlen(s)));
}
return 0;
}