zoukankan      html  css  js  c++  java
  • 马拉车,O(n)求回文串

    马拉车,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)。
      2id-i,将其转化到x坐标上看,正好是i关于id的对称点,可以这么理解:由于mx>i,可知i-->mx是在已知范围以内的,因为以i为回文中心的回文串是与以其关于对称点j=2id-i存在长度至少为mx-i相同回文半径的。
      如图:(x和y至少是同样长的,因为以j为中心的是回文串,同id同i,根据回文串性质可得)

    • 第四步:对于p数组的认识,p数组是在原字符串翻倍后的基础上进行运算的,很显然,若p[i]=6,那么原串的回文长度(不是回文半径)是5 :设原半径为ans,回文长度为len,那么len=ans2-1;而此时半径为x=ans2,转化可得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);
        }
    }
    
  • 相关阅读:
    LinkedList源码分析
    Hashtable源码分析
    String源码分析
    记一次ArrayList产生的线上OOM问题
    【spring源码分析】IOC容器初始化——查漏补缺(五)
    前端面试的那些事儿(1)~JavaScript 原始数据类型
    前端面试的那些事儿(2)~ 不再害怕被问 JavaScript 对象
    第二周技术周报-前端的自我修养
    第一周技术周报-前端框架演变
    JavaScript数据类型检测 数组(Array)检测方式
  • 原文地址:https://www.cnblogs.com/zsyacm666666/p/6527635.html
Copyright © 2011-2022 走看看