首页 > 代码库 > 马拉车,O(n)求回文串

马拉车,O(n)求回文串

<style>body { font-family: sans-serif; font-size: 14px; line-height: 1.6; padding-top: 10px; padding-bottom: 10px; background-color: white; padding: 30px } body>*:first-child { margin-top: 0 !important } body>*:last-child { margin-bottom: 0 !important } a { color: #4183C4 } a.absent { color: #cc0000 } a.anchor { display: block; padding-left: 30px; margin-left: -30px; cursor: pointer; position: absolute; top: 0; left: 0; bottom: 0 } h1,h2,h3,h4,h5,h6 { margin: 20px 0 10px; padding: 0; font-weight: bold; cursor: text; position: relative } h1:hover a.anchor,h2:hover a.anchor,h3:hover a.anchor,h4:hover a.anchor,h5:hover a.anchor,h6:hover a.anchor { text-decoration: none } h1 tt,h1 code,h2 tt,h2 code,h3 tt,h3 code,h4 tt,h4 code,h5 tt,h5 code,h6 tt,h6 code { font-size: inherit } h1 { font-size: 28px; color: black } h2 { font-size: 24px; border-bottom: 1px solid #cccccc; color: black } h3 { font-size: 18px } h4 { font-size: 16px } h5 { font-size: 14px } h6 { color: #777777; font-size: 14px } p,blockquote,ol,dl,table,pre { margin: 15px 0 } ul { margin: 0 } hr { background: transparent repeat-x 0 0; border: 0 none; color: #cccccc; height: 4px; padding: 0 } body>h2:first-child { margin-top: 0; padding-top: 0 } body>h1:first-child { margin-top: 0; padding-top: 0 } body>h1:first-child+h2 { margin-top: 0; padding-top: 0 } body>h3:first-child,body>h4:first-child,body>h5:first-child,body>h6:first-child { margin-top: 0; padding-top: 0 } a:first-child h1,a:first-child h2,a:first-child h3,a:first-child h4,a:first-child h5,a:first-child h6 { margin-top: 0; padding-top: 0 } h1 p,h2 p,h3 p,h4 p,h5 p,h6 p { margin-top: 0 } li p.first { display: inline-block } ul,ol { padding-left: 30px } ul:first-child,ol:first-child { margin-top: 0 } ul:last-child,ol:last-child { margin-bottom: 0 } dl { padding: 0 } dl dt { font-size: 14px; font-weight: bold; font-style: italic; padding: 0; margin: 15px 0 5px } dl dt:first-child { padding: 0 } dl dt>:first-child { margin-top: 0 } dl dt>:last-child { margin-bottom: 0 } dl dd { margin: 0 0 15px; padding: 0 15px } dl dd>:first-child { margin-top: 0 } dl dd>:last-child { margin-bottom: 0 } blockquote { border-left: 4px solid #dddddd; padding: 0 15px; color: #777777 } blockquote>:first-child { margin-top: 0 } blockquote>:last-child { margin-bottom: 0 } table { border-collapse: collapse; padding: 0 } table tr { border-top: 1px solid #cccccc; background-color: white; margin: 0; padding: 0 } table tr:nth-child(2n) { background-color: #f8f8f8 } table tr th { font-weight: bold; border: 1px solid #cccccc; text-align: left; margin: 0; padding: 6px 13px } table tr td { border: 1px solid #cccccc; text-align: left; margin: 0; padding: 6px 13px } table tr th:first-child,table tr td:first-child { margin-top: 0 } table tr th:last-child,table tr td:last-child { margin-bottom: 0 } img { max-width: 100% } span.frame { display: block; overflow: hidden } span.frame>span { border: 1px solid #dddddd; display: block; float: left; overflow: hidden; margin: 13px 0 0; padding: 7px; width: auto } span.frame span img { display: block; float: left } span.frame span span { clear: both; color: #333333; display: block; padding: 5px 0 0 } span.align-center { display: block; overflow: hidden; clear: both } span.align-center>span { display: block; overflow: hidden; margin: 13px auto 0; text-align: center } span.align-center span img { margin: 0 auto; text-align: center } span.align-right { display: block; overflow: hidden; clear: both } span.align-right>span { display: block; overflow: hidden; margin: 13px 0 0; text-align: right } span.align-right span img { margin: 0; text-align: right } span.float-left { display: block; margin-right: 13px; overflow: hidden; float: left } span.float-left span { margin: 13px 0 0 } span.float-right { display: block; margin-left: 13px; overflow: hidden; float: right } span.float-right>span { display: block; overflow: hidden; margin: 13px auto 0; text-align: right } pre,code,tt { font-size: 12px; font-family: Consolas, "Liberation Mono", Courier, monospace } code,tt { margin: 0; padding: 0 5px; white-space: nowrap; border: 1px solid #eaeaea; background-color: #f8f8f8 } pre code { margin: 0; padding: 0; white-space: pre; border: none; background: transparent } .highlight pre { background-color: #f8f8f8; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px } pre { background-color: #f8f8f8; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px } pre code,pre tt { background-color: transparent; border: none }</style>

马拉车,O(n)求回文串

对整个马拉车算法步骤做个总结:

  • 第一步:将每个原字母用两个特殊字符包围如:

    aaa --> #a#a#a#
    abab -->#a#b#a#b 
    同时可以由这个翻倍的字符串得到一个性质:
    如果在此串中,以特殊字符,如‘#‘为回文中心,那么在原串中回文长度就是偶数,如果是以正常字符为回文中心,那么在原串中的回文长度就是奇数
    

    这样可以使得所有的奇数长度的回文串变成偶数长度

  • 第二步:设置P数组P[N*3];代表S[i]的回文半径(包括自身),并设置id为迄今为止回文半径最大的字符位置,max为id+P[id],该回文串的右边界位置

  • 第三步:求p数组,这里存在一个结论: 如果mx > i,那么P[i] >= min(P[2 * id - i], mx - i)。 2*id-i,将其转化到x坐标上看,正好是i关于id的对称点,可以这么理解:由于mx>i,可知i-->mx是在已知范围以内的,因为以i为回文中心的回文串是与以其关于对称点j=2*id-i存在长度至少为mx-i相同回文半径的。 如图:(x和y至少是同样长的,因为以j为中心的是回文串,同id同i,根据回文串性质可得)

    技术分享

     

  • 第四步:对于p数组的认识,p数组是在原字符串翻倍后的基础上进行运算的,很显然,若p[i]=6,那么原串的回文长度(不是回文半径)是5 :设原半径为ans,回文长度为len,那么len=ans*2-1;而此时半径为x=ans*2,转化可得len=x-1;

这里贴上两份模板

模板1:

void init()
{
    len1=strlen(s);
    str[0]=‘(‘;
    str[1]=‘#‘;
    for(int i=0;i<len1;i++)
    {
        str[i*2+2]=s[i];
        str[i*2+3]=‘#‘;
    }
    len2=len1*2+2;
    str[len2]=‘)‘;
}
void Manacher()
{
    memset(p,0,sizeof(p));
    int id=0,mx=0;
    for(int i=1;i<len2;i++)
    {
        if(mx>i) p[i]=min(mx-i,p[2*id-i]);
        else p[i]=1;
        for(;str[i+p[i]]==str[i-p[i]];p[i]++);
        if(p[i]+i>mx)
        {
            mx=p[i]+i;
            id=i;
        }
    }
}

模板2:

int Init(int n)
{
    cpy[0]=‘(‘;cpy[1]=‘#‘;
    for(int i=0,j=2;i<n;j+=2,i++)
    {
        cpy[j]=a[i];
        cpy[j+1]=‘#‘;
    }
    n=n*2+3;
    cpy[n-1]=‘)‘;
    return n;
}
void Manacher(char *s,int n,int *p)
{
    for(int i=1,j=0,k;i<n;i+=k)
    {
        while(s[i-j-1]==s[i+j+1]) j++;
        p[i]=j;
        for(k=1;k<=p[i]&&p[i-k]!=p[i]-k;k++)
        {
            p[i+k]=min(p[i-k],p[i]-k);
        }
        j=max(j-k,0);
    }
}

马拉车,O(n)求回文串