求回文子串长:Manacher算法(马拉车算法)

算法问题描述

求回文子串

算法思想

字符串的思想一般都是用前面求过的加速后面的,马拉车算法也不例外,先强行搞一个东西,在每个字符中间插入一个不会出现的字符‘#‘’’以处理奇回文和偶回文(代码方便)
如果现在有一个大的以id为对称轴的回文串,现在要更新id右边的某个i的最大回文半径,如果i在id回文串内,是不是可以直接用i的关于id的对称点的回文半径呢?
所以我们分情况讨论一下。记i的关于id的对称点为j,回文半径为p[i]-1(代码方便)
1.j的回文串超过id的回文串,那么i的回文串半径就等于j在i里面的回文半径,因为!!!如果i的回文串也超过id的回文串,那么id的回文串应该更长一点
2.j的回文串在id的回文串里面,那么显然barabara,p[i]=p[j]
3.j的回文串刚好贴着id的回文串,那么p[i]=p[j],并且!!!!,p[i]有增长的空间,要p[i]++去试
答案要去掉’#’,所以通过计算(听别人说),刚刚好就是p[i]-1

代码

int n,m,p[maxn];
char _ch[maxn],ch[maxn]={};
int init(){
    int cnt=0;
    scanf("%s",_ch+1);
    int len=strlen(_ch+1);
    ch[++cnt]='$';
    for(int i=1;i<=len;i++){
        ch[++cnt]='#';
        ch[++cnt]=_ch[i];
    }
    ch[++cnt]='#';
    ch[++cnt]='\0';
}
void Manacher(){
    int len=strlen(ch+1),id,mx=0;
    for(int i=2;i<=len;i++){
        if(i<mx) p[i]=min(p[2*id-i],mx-i);
        else p[i]=1;
        while(ch[i-p[i]]==ch[i+p[i]]) p[i]++;
        if(mx<i+p[i]) mx=i+p[i],id=i;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_32461955/article/details/81878327