题意:给一个字符串,求出它的最长回文子串的长度
这个hash+二分也能做,不过manacher比hash的那种方式代码简单点,而且效率高很多
一个几千毫秒,一个几百毫秒
马拉车的介绍https://blog.csdn.net/dyx404514/article/details/42061017
这博客写得有水平有质量。我刚刚开始的时候没有看懂if(mx>i)的部分
因为mx后面的没有求出,所以要保证len[i]小于mx,如果len[i]实际上是大于mx-i的,那么后面的while再更新len[i],并且考虑对称性,如果mx>i,len[i]一定是小于等于len[op*2-i]。
在设置边界的时候,左右边界的字符不能一样。
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#include<queue>
#include<map>
using namespace std;
char s[1000005],ts[2000050];//转换后的数组是2n+1的长度
int n,len[2000005];
void trans()
{
n=strlen(s+1);//s+1,而不是s,从s+1开始输入的字符串
int i=0;
ts[0]='@';//设置一个边界,防止越界
for(i=1;i<=2*n;i+=2)
{
ts[i]='#';
ts[i+1]=s[(i+1)/2];//插入#
}
ts[2*n+1]='#';
ts[2*n+2]='$';//数组后面的边界
ts[2*n+3]=0;
}
int manacher()
{
int MAX=0,op=0,i,ans=0;//MAX是前面回文子串的最右边
for(i=1;i<=2*n+1;i++)//op是有右边界MAX的回文子串中心的下标
{
if(MAX>i)
{
if(MAX-i>len[2*op-i])
len[i]=len[2*op-i];
else len[i]=MAX-i;
}//取MAX-i和i关于op对称的len的最小值
//不让i现在超过MAX,并且在op-MAX到op+MAX都是回文,保证对称性
else len[i]=1;//从头开始
while(ts[i-len[i]]==ts[i+len[i]])//回文子串从i往外扩展
len[i]++;
if(MAX<len[i]+i)
{
MAX=len[i]+i;
op=i;
}//更新MAX和op
if(ans<len[i]-1)ans=len[i]-1;
}
return ans;
}
int main()
{
int i,cas=0,a;
while(scanf("%s",s+1)==1)//从s+1开始输入
{
if(s[1]=='E')break;
trans();
a=manacher();
printf("Case %d: %d\n",++cas,a);
}
return 0;
}