manacher算法小结

下路认真看了半个小时,才看懂了。。。(:зゝ∠)
看来还是太弱了(。・・)ノ
老套路,一道题目,引入算法。


题目hdu3068

链接http://acm.hdu.edu.cn/showproblem.php?pid=3068
给你一堆字符串,让你判断其最长的回文子串的长度。
回文子串是啥就不用说了吧。。。。


manacher算法

首先不得不说这个算法吼巧妙O(∩_∩)O~
首先对于一个字符串s=abcdsdcabc,长度有奇偶两种情况。
这个算法规定在每一个字符前后插入一个同样的字符。
如上述更换后,s=#a#b#c#d#s#d#c#a#b#c#。
这样将字符串都转化为奇数处理了。(o_ _)ノ
为了方便处理越界情况,我们在前面加一个特殊的符号。
于是最终变成s=$#a#b#c#d#s#d#c#a#b#c#(似乎变成了偶数。。)

然后我们定义一个数组p[i],表示当前以i为回文串的中心,向右最多延伸的长度。
那么上面的
s= $#a#b#c#d#s#d#c#a#b#c#
p=1,1,2,1,2,1,2,1,4,1,2,1,2,1,2,1,2,1,2,1,2,1
p[i]=1就表示不能延伸,只能是自己。
可以发现max(p[i])-1就是原串中的最长回文子串。
我们的目的就是在短时间内求出p[i]。

我们算法是从前往后扫,就是说我们求p[i]时,p[1~i-1]都是求出来了。
我们设mx表示在前i-1中,回文串向右延伸到最长的位置,并把这个回文串的中心位置记为id。
那么id+p[id]就是这个回文串向右最长延伸到的位置。

就是我们求i时,如果mx>i,意思就是当前i处于id为中心的回文串的范围内。
1.那么对于id这个回文串有s[id+1~p[id]]=s[id-1~p[id]],所以i 与 i关于id的对称点j是一样的,那么以j为中心的字符串我们已经求得了,那么j的情况自然就是i的情况。所以直接得p[i]=p[j];
2.j这个回文串向右延伸的长度为p[j],但i+p[j]可能已经大于mx了,那么这就是不合法的,因为mx后面的情况我们都不知道。此时p[i]=mx-i;
综上:p[i]=min(p[j],mx-i)别问我j怎么求╭(╯^╰)╮。

这幅图其实说的很清楚了。
这里写图片描述
这个算法复杂度是O(n)的。很优秀。
需要注意的是新字符串和p的数组的范围。


代码

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)

using namespace std;

const int maxn=1e5+10035;
char ch[maxn],now[maxn*2];
int p[maxn*2],ans;

int main()
{
    freopen("T.in","r",stdin);
    while (scanf("%s",&ch)!=EOF){
        int len=0,len1=strlen(ch);
        now[0]='$';
        fo(i,0,len1-1){
            now[++len]='#';
            now[++len]=ch[i];
        }
        now[++len]='#';
        getchar();
        p[0]=1; ans=0;
        int id=0,mx=1;
        fo(i,1,len){
            if (mx>i) p[i]=min(p[2*id-i],mx-i);
            else p[i]=1;
            while (now[i+p[i]]==now[i-p[i]]) ++p[i];
            if (p[i]+i>mx){
                mx=p[i]+i;
                id=i;
            }
            if (p[i]>ans) ans=p[i];
        }
        printf("%d\n",ans-1);
    }
    return 0;
} 

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值