Manacher总结

【介绍】

Manacher可以线性解决最长回文子串的问题。

【思想】

Ps:用Manacher的时候,我们可以想到一个小办法减轻代码的长度,就是在每个字符之间加一个另类的字符也就是不同于其他字符的字符(比如处理只包含小写字母的字符串我们可以添加‘~’,首位也加。例如aba变成了~a~b~a~),这样原串中的所有字符都处在偶位,容易处理(否则就要判断是奇数长度的回文串还是偶数长度的回文串)。但是这个小办法也有负面也就是提高了空间复杂度。但加了以后代码非常好写,博主比较推荐

定义 p[x] 表示目前在第x位,向两边能推到的最大距离。

定义 Pos 表示目前的中点, R 表示从中点所能推到的最大右端点,L R 关于Pos的对称点。

我们该如何得出 p[x] 的转移方程。分类讨论,如下:

①: x<R

x 的对称点为y,那么 y=2Posx ,因为已经推出了 p[y] ,所以 p[x]=p[y]

但是有一种情况要考虑,如果 yp[y]<L ,那么就已经越界了,所以只能推到 yL Rx

所以 p[x]=min(p[2Posx],Rx)

②: x>=R

这时候就只能暴力往后退,然后更新 Pos R <script type="math/tex" id="MathJax-Element-58">R</script>。

综上所述,很容易发现时间复杂度是线性的。

【模板】

int Manacher(char *s)
{
    int len=strlen(s+1);
    for (int i=1; i<=len; i++) c[2*i-1]='~',c[2*i]=s[i]; c[len=2*len+1]='~';
    int Pos=0,R=0,MAX=0;
    for (int i=1; i<=len; i++)
    {
        if (i<R) p[i]=min(p[2*Pos-i],R-i); else p[i]=1;//判断类别 
        while (1<=i-p[i]&&i+p[i]<=len&&c[i-p[i]]==c[i+p[i]]) p[i]++;//暴力往后推 
        if (i+p[i]>R) {R=i+p[i]; Pos=i;}//更新Pos和R 
        MAX=max(MAX,p[i]-1);
    }
    return MAX;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值