Manacher算法俗称马拉车算法,是一个可以在线性时间复杂度求解最长回文子串的算法。
要优化字符串算法,一般都是要利用之前匹配出来的信息以减少计算次数,这里用到了回文串回文的性质,令
f[i]
表示以
i
这个位置为对称点的回文串的长度整除
f[i]=min(f[2∗j−i],R−i)
,显然,如果
f[i]
的取值是前一个,那么就最终的
f[i]
就是它,但是,如果取的是后一个,说明有需要的信息没有获得,就要从这个位置开始往后枚举了。否则,如果
i>R
,说明计算
f[i]
所需的信息完全没有获得,就直接暴力枚举就可以了。
那么,这个算法为什么是线性复杂度呢?显然,如果暴力枚举,每往后多枚举一个, R 至少加1,而 R 显然增加的次数只能是 O(N) 次,所以整个马拉车算法的复杂度也为 O(N) 。
模板题的话,可以去做hihoCoder1032
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 2000006
using namespace std;
inline char nc(){
static char buf[100000],*i=buf,*j=buf;
return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
char ch=nc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
int n,tet,f[maxn];
char a[maxn];
int main(){
freopen("manacher.in","r",stdin);
freopen("manacher.out","w",stdout);
tet=_read();
while(tet--){
n=0;char ch=nc();
while(ch!='\n'&&ch!=EOF)a[(++n)*2]=ch,ch=nc();
for(int i=1;i<=n+1;i++)a[i*2-1]='%';
n=n*2+1;
memset(f,0,sizeof(f));
int R=0,j=0;
for(int i=1;i<=n;i++){
if(i<=R)f[i]=min(f[2*j-i],R-i);
while(f[i]<n-i&&f[i]<i-1&&a[i-f[i]-1]==a[i+f[i]+1])f[i]++;
if(i+f[i]>R)R=i+f[i],j=i;
}
int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,f[i]);
printf("%d\n",ans);
}
return 0;
}