Manacher算法—简介

Manachar是一个求最长回文子串的算法,时间复杂度O(n)。

 

第一步,扩充原字符串

我们在每个字符的两旁分别加上一个不曾出现的符号(如#),这样做虽然增长了字符串的长度(记得开两倍空间),但使字符串变成了奇数长度的字符串,便于统一地进行操作。而且原字符串的回文性质也没有改变。

 

第二步,继承前面的状态

这步是利用了回文串左右对称的性质。在一个大回文串中,中心为id,右边有一点i,左边有一点i',它们关于id对称。如果我们求得了i'的最长回文子串,i的最长回文子串也可以直接求得。

我们刚刚说的是上面那种情况,是完全在mx里面的情况。
中间的是部分超出的情况。由于i’的回文子串超出了mx',对应的,i的也应该超出mx。但是对于mx外的世界是未知的,我们不能贸贸然地认为超出这一段一定与内部这段对称,所以最多只能扩展到mx,外面的暂且不要贪心地收下。
对于下面的情况就完全没法继承了,i已经完全超出了mx,只能交由下一步(暴力)来处理。

 

第三步,暴力扩展回文串

放下的部分我们直接暴力比对,注意要控制边界。
怎么样的子串需要暴力扩展呢?是那些一定程度上超出了mx的子串,如图中、下两种情况。

 

第四步,更新最远边界

记下mx(目前最远边界)和id(其中心),mx的意义是我们目前最远暴力比对到的地方

 

第四步,计算实际回文串长度

因为其中存在了无意义的符号,我们要除去其干扰来求有意义的部分长。具体看代码,画画图自己也是可以总结归纳出来的。

 

例题(poj 3974)

题意     求最长回文串。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxl=1000010;

char ss[maxl];int len;
char s[2*maxl];int nlen;//记录新的字符串                                               \ 两倍空间 
int f[2*maxl];//f[i]表示以i为中心往两边最大扩展多少仍是回文串,即[i-f[i],i+f[i]]是个回文串  /

int main()
{
    int T=0;
    while(scanf("%s",ss+1),ss[1]!='E')
    {
        len=strlen(ss+1);nlen=0;
        for(int i=1;i<=len;i++)
        {
            s[++nlen]='#';//扩充原字符串
            s[++nlen]=ss[i];
        }
        s[++nlen]='#';
        
        int id,mx=0;
        for(int i=1;i<=nlen;i++)
        {
            if(i<=mx) f[i]=min(mx-i,f[id-(i-id)]);//继承前面的状态
            else f[i]=1;
            while(i+f[i]+1<=nlen && i-f[i]-1>=1 && s[i+f[i]+1]==s[i-f[i]-1]) f[i]++;//暴力扩展回文串 
            if(i+f[i]>mx) id=i,mx=i+f[i];//更新最远边界 
        }
        
        int ans=0;//计算实际回文串长度
        for(int i=1;i<=nlen;i++)
        {
            int tmp=f[i]/2*2;
            if(s[i]!='#') tmp++;
            ans=max(ans,tmp);
        }
        printf("Case %d: %d\n",++T,ans);
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值