码迷,mamicode.com
首页 > 其他好文 > 详细

关于字符串问题【Manacher】

时间:2017-09-17 17:32:58      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:说明   char   ret   algo   for   mil   偶数   i++   style   

Manacher是用来求最长回文子串的。做法很好理解,有一点贪心的感觉。

解释一下加#号
字符串abbaba,abba和aba都回文子串,但是一个长度是奇数,一个是偶数,直接做还要分情况讨论。如果变成#a#b#b#a#b#a#,那#a#b#b#a#和#a#b#a# 长度都是奇数,而且开头结尾都是#号,这样比较方便。

具体的做法结合代码、注释就可以理解了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int p[210000],L[210000],R[210000];
//p[i]表示以i为中心所形成的回文串的i~R的长度
//L(R)[i]代表以i为中心所形成的最长回文子串的最左(右)点 
//显然p[i]=R[i]-i+1或i-L[i]+1 
char s[210000],now[210000];//now表示加了#号形成的新字符串
int main()
{
    while(scanf("%s",s+1)!=EOF)
    {
        int len=strlen(s+1);//字符之间的间隙加上#号,两种情况:abba和aba就合为一种了 
        for(int i=1;i<=len;i++){now[2*i-1]=#;now[2*i]=s[i];}
        len=len*2+1;now[len]=#;
        
        int k=0;//k表示目前能到达最远点的回文串的中心(R最大) 
        L[k]=0;R[k]=0;
        for(int i=1;i<=len;i++)
        {
            int j=k-(i-k);//j为i关于k的对称点
            if(i<=R[k])p[i]=min(p[j],j-L[k]+1);//i在以k为中心的回文串里 
            //L[k]~j~k~i~R[k]
            //如果L[k]<L[j],那说明j整个回文串都在k里,那i就和j一样
            //否则就只能确定从L[k]~j是可以回文的 
            else p[i]=1;//不然就要暴力枚举
            while(1<=i-p[i]&&i+p[i]<=len&&now[i-p[i]]==now[i+p[i]])p[i]++;//向左右枚举,更新p[i]
            L[i]=i-p[i]+1;R[i]=i+p[i]-1;
            if(R[i]>R[k])k=i;
        }
        int ans=0;
        for(int i=1;i<=len;i++)ans=max(ans,p[i]-1);
        printf("%d\n",ans);
        /*
        当前的最长回文子串长度为2*p[i]-1
        因为#号处于首尾和每个字符之间,所以我们就可以保证所得出的最长回文子串的首尾都为#
        这时我们可以得出不带#号的回文串的长度为(2*p[i]-1-1)/2=p[i]-1
        所以真正的最长回文子串就是p[i]-1
        */
    }
    return 0;
}

 

关于字符串问题【Manacher】

标签:说明   char   ret   algo   for   mil   偶数   i++   style   

原文地址:http://www.cnblogs.com/AKCqhzdy/p/7536086.html

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