先在每两个相邻字符中间插入一个分隔符,当然这个分隔符要在原串中没有出现过。一般可以用‘#’分隔。这样就非常巧妙的将奇数长度回文串与偶数长度回文串统一起来考虑了(见下面的一个例子,回文串长度全为奇数了)
并且最开始加一个'$'字符,防止越界; 至于'#'字符,应该在最前面和最后面都要加,且不能忽视(n长度要算在这个位置后面),一个符合的情况 $ # a # a # a # a #
p[i]表示从i开始的向左或向右的最长匹配长度
这里有一个很好的性质,P[id]-1就是该回文子串在原串中的长度(包括‘#’)
原理:http://blog.sina.com.cn/s/blog_70811e1a01014esn.html 其图片分三种情况介绍写的很好
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,p[300005];
char ch[300005],s[300005];
int long_hw(char *s,int n)
{
int id=0,mx=0,ans=0;
memset(p,0,sizeof(p));
for (int i=1;i<n;i++)
{
if (mx>i)//mx表示id能伸展的最大限度后面那个字符
p[i]=min(p[id-(i-id)],mx-i);
else p[i]=1;
while (s[i-p[i]]==s[i+p[i]]) p[i]++;//因为s【i】就算一个长度为1的,所以左右如果对称,就可以加加,
if (i+p[i]>mx)//更新
{
id=i;
mx=i+p[i];
}
ans=max(ans,p[i]);
}
return ans-1;//答案要减一,因为原长度等于p【i】-1
}
int main()
{
while (scanf("%s",ch)!=EOF)
{
int len=strlen(ch);
memset(s,0,sizeof(s));
n=0;
s[0]='$';
for (int i=0;i<len;i++)
s[++n]='#',s[++n]=ch[i];
s[++n]='#';//注意第一个地方和最后一个地方都必须是‘#’
printf("%d\n",long_hw(s,n+1));
}
return 0;
}