Manacher算法

Manacher算法俗称马拉车算法,是一个可以在线性时间复杂度求解最长回文子串的算法。

要优化字符串算法,一般都是要利用之前匹配出来的信息以减少计算次数,这里用到了回文串回文的性质,令 f[i] 表示以 i 这个位置为对称点的回文串的长度整除2,我们在循环的时候记一个 R 表示当前最右边的回文串的右边界,j表示这样的回文串的中间点(我们假设所有的回文串都是奇数位的,偶数位的可以通过往相邻的字符串之间塞奇怪的字符,如 % 来凑位)。这样,利用回文串的性质,如果 iR ,我们可以知道

f[i]=min(f[2ji],Ri)
,显然,如果 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值