最长回文
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 12145 Accepted Submission(s): 4458
Problem Description
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
回文就是正反读都是一样的字符串,如aba, abba等
Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
Sample Input
aaaa abab
Sample Output
4 3
Source
参考:manacher算法
算法的基本思路是这样的:把原串每个字符中间用一个串中没出现过的字符分隔#开来(统一奇偶),
同时为了防止越界,在字符串的首部也加入一个特殊符,但是与分隔符不同。
同时字符串的末尾也加入′\0′。
算法的核心:用辅助数组p记录以每个字符为核心的最长回文字符串半径。
也就是p[i]记录了以str[i]为中心的最长回文字符串半径。p[i]最小为1,
此时回文字符串就是字符串本身。示例:原字符串′abba′,处理后的新串′#a#b#b#a#\0’,
得到对应的辅助数组p=[0,1,1,2,1,2,5,2,2,1]。
#include
#include
#include
using namespace std;
#define N 1000010
char str[N];
char tmp[N<<1];
int len[N<<1];
int main()
{
int t=1,i,l;
while(scanf("%s",str)==1)
{
l=strlen(str);
l*=2;
tmp[0]='@';
for(i=1; i<=l; i+=2)
{
tmp[i]=0;
tmp[i+1]=str[i>>1];
}
tmp[l+1]=0;
tmp[l+2]='$'; ///防止越界
tmp[l+3]=0;
l++;
int id=0; ///id当前len[i]的最大位置i
int mx=0; ///mx即为当前计算回文串最右边字符的最大值
int ans=0; ///回文串最大值
for(i=1; i<=l; i++)
{
len[i]=mx
=mx,要从头开始匹配
while(tmp[i+len[i]]==tmp[i-len[i]])
len[i]++;
if(len[i]+i>mx)///若新计算的回文串右端点位置大于mx,要更新id和mx的值
{
mx=len[i]+i;
id=i;
}
ans=ans>len[i]?ans:len[i];///1~i回文串最大值
}
printf("%d\n",ans-1);
}
return 0;
}