码迷,mamicode.com
首页 > 编程语言 > 详细

马拉车算法详解

时间:2020-07-17 22:10:08      阅读:116      评论:0      收藏:0      [点我收藏+]

标签:序列   pen   等于   onclick   div   ace   man   get   include   

简述

  Manacher算法,又称马拉车算法,它是用于求一个字符串的最长回文子串长度的算法,时间和空间复杂度为O(n)。

算法思想

  求一个字符串的最长回文子串长度,我们如果用暴力来做,我们就要取出这个串的所有子串,然后判断这个子串是不是回文串,复杂度是n方的。

  那么马拉车为何如此神奇能做到O(n)呢?

  首先我们来看这两个串:abba和abcba。第一个串的回文中心在两个b之间,第二个串的回文中心为字符c,这样两种情况我们分类讨论太麻烦了,所以我们考虑对原字符串进行一个字符填充,abba->@#a#b#b#a#0 ,abcba->@#a#b#c#b#a#0,这样他们都变成了奇数,讨论的情况就一致了。

  由此我们可以写出重定义字符串的代码:

void getstr()
{//重定义字符串,s为原字符串,str为新串,len为s串长度 
    int k=0;
    str[k++]=@;
    for(int i=0;i<len;i++){
        str[k++]=#;
        str[k++]=s[i];
    } 
    str[k++]=#;
    str[k++]=0;
    len=k;
}

  首先我们规定几个变量的含义:len[i]为以i为中心点的最长回文序列的回文半径,po为当前中心点,p为当前回文子串的右边界。  

  我们可以得出,ans=len[i]-1,因为加入填充字符后的str的最长回文串为2*len[i]-1,又因为#号的个数比原字符多一个,所以#字符的总数为len[i]个,故原字符的最长回文子串为len[i]-1个。

  当i<=p时,找到i相对于po的对称点j,如果len[j]<p-i,如下图:

  技术图片

  由对称性得知,i和j左右的字符是一样的,所以len[i]=len[j]。

  如果len[j]>=p-i,由对称性,说明以i为中心的回文串会扩散至p以外,而大于p部分的串我们还没用匹配,所以我们一个一个匹配,更新po和len[i]。

  技术图片

  当i>p时,说明以i为中心的回文串一点都没匹配,就只能老老实实一个一个匹配了。

  技术图片

  所以我们可以写出如下匹配部分代码:

int manacher(){
    int mx=0,id;
    int maxx=0;
    for(int i=0;i<len;i++){
        if(i<mx) len[i]=min(mx-i,len[2*id-i]);//i在mx左边,取在边界以内且较小的那段 
        else len[i]=1;//i在mx右边,所以直接等于1 
        while(str[i+len[i]]==str[i-len[i]]) len[i]++;//向右一个个匹配 
        if(i+len[i]>mx){
            mx=i+len[i];
            id=i;
            maxx=max(maxx,len[i]-1);
        }
    }
    return maxx;
} 

模板

技术图片
#include<iostream>
#include<string.h> 
using namespace std;
const int maxn=11000002;
char s[maxn<<1],str[maxn<<1];
int len,num[maxn*2];
void getstr()
{//重定义字符串,s为原字符串,str为新串,len为s串长度 
    int k=0;
    str[k++]=@;
    for(int i=0;i<len;i++){
        str[k++]=#;
        str[k++]=s[i];
    } 
    str[k++]=#;
    str[k++]=0;
    len=k;
}
int manacher(){
    int mx=0,id;
    int maxx=0;
    for(int i=0;i<len;i++){
        if(i<mx) num[i]=min(mx-i,num[2*id-i]);//i在mx左边,取在边界以内且较小的那段 
        else num[i]=1;//i在mx右边,所以直接等于1 
        while(str[i+num[i]]==str[i-num[i]]) num[i]++;//向右一个个匹配 
        if(i+num[i]>mx){
            mx=i+num[i];
            id=i;
            maxx=max(maxx,num[i]-1);
        }
    }
    return maxx;
} 
int main()
{
    cin>>s;
    len=strlen(s);
    getstr();
    cout<<manacher();
    return 0;
}
View Code

 

马拉车算法详解

标签:序列   pen   等于   onclick   div   ace   man   get   include   

原文地址:https://www.cnblogs.com/qq2210446939/p/13332685.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!