zoukankan      html  css  js  c++  java
  • 扩展KMP

    https://wenku.baidu.com/view/206c8178d0d233d4b04e69ed.html

     

    问题定义:给定两个字符串S和T(长度分别为n和m),下标从0开始,定义extend[i]等于S[i]...S[n-1]与T的最长公共前缀的长度,求出所有的extend[i]。举个例子,看下表:

    i01234567
    S a a a a a b b b
    extend[i] 5 4 3 2 1 0 0 0
    T a a a a a c

      为什么说这是KMP算法的扩展呢?显然,如果在S的某个位置i有extend[i]等于m,则可知在S中找到了匹配串T,并且匹配的首位置是i。而且,扩展KMP算法可以找到S中所有T的匹配。接下来具体介绍下这个算法。

    计算extend[1]= 10 时,我们得到S[1...10] = T[1...10] S[2...10] = T[2...10]

    那么计算extend[2]时 是从S[2]开始 匹配的开头阶段是 以T[2...10]为母串,T为子串的匹配

    辅助数组next[i]表示T[i...m]与T的最长公共前缀长度

    对上面的例子 next[2]= 10   =》 T[2...11] = T[1...10]  =>  T[2...10] = T[1...9]

    所以计算extend[2]时 我们可以直接从S[11] -- T[10]开始比较 发现失配 所以extend[2] = 9

     

     

    算法:O(n+m)

     

    计算next数组  以T为母串,T为子串的一个特殊的扩展KMP

     

     

    应用:

    求最长公共前缀长度

    求字符串中重复子串的长度  i+next[i]

        abababccc中ababab就是重复子串,ababa也是重复子串【端点处循环节不完整的也算】

        比如ababab next[2] = 4   2,3匹配0,1 4,5匹配2,3相当于还是匹配0,1 只要能匹配上的就是在重复前i个字符 能匹配多长就重复了多长 总长就是i+next[i]

     

    代码模板

    void GetExtend(const EleType str[], int strLen, int extend[], const EleType mode[], int modeLen, int next[])
    {
        int i, a, p, j(-1);
        for(i = 0; i < strLen; ++i,--j){
            if(j < 0 || i + next[i - a] >= p){
                if(j < 0) j = 0, p = i;
                while(p < strLen && j < modeLen && str[p] == mode[j])
                    ++p,++j;
                extend[i] = j, a = i;
            }
            else extend[i] = next[i - a];
        }
    }
    const int maxn=100010;   //字符串长度最大值  
    int next[maxn],ex[maxn]; //ex数组即为extend数组  
    //预处理计算next数组  
    void GETNEXT(char *str)  
    {  
        int i=0,j,po,len=strlen(str);  
        next[0]=len;//初始化next[0]  
        while(str[i]==str[i+1]&&i+1<len)//计算next[1]  
        i++;  
        next[1]=i;  
        po=1;//初始化po的位置  
        for(i=2;i<len;i++)  
        {  
            if(next[i-po]+i<next[po]+po)//第一种情况,可以直接得到next[i]的值  
            next[i]=next[i-po];  
            else//第二种情况,要继续匹配才能得到next[i]的值  
            {  
                j=next[po]+po-i;  
                if(j<0)j=0;//如果i>po+next[po],则要从头开始匹配  
                while(i+j<len&&str[j]==str[j+i])//计算next[i]  
                j++;  
                next[i]=j;  
                po=i;//更新po的位置  
            }  
        }  
    }  
    //计算extend数组  
    void EXKMP(char *s1,char *s2)  
    {  
        int i=0,j,po,len=strlen(s1),l2=strlen(s2);  
        GETNEXT(s2);//计算子串的next数组  
        while(s1[i]==s2[i]&&i<l2&&i<len)//计算ex[0]  
        i++;  
        ex[0]=i;  
        po=0;//初始化po的位置  
        for(i=1;i<len;i++)  
        {  
            if(next[i-po]+i<ex[po]+po)//第一种情况,直接可以得到ex[i]的值  
            ex[i]=next[i-po];  
            else//第二种情况,要继续匹配才能得到ex[i]的值  
            {  
                j=ex[po]+po-i;  
                if(j<0)j=0;//如果i>ex[po]+po则要从头开始匹配  
                while(i+j<len&&j<l2&&s1[j+i]==s2[j])//计算ex[i]  
                j++;  
                ex[i]=j;  
                po=i;//更新po的位置  
            }  
        }  
    }  
    
    
    



  • 相关阅读:
    PHP定时备份MySQL,mysqldump语法大全
    虚拟机拷贝之后,发现系统内的开机自启动的nginx,不能自启动了
    八:二叉搜索树的后序遍历
    配置Ubuntu开发环境
    poj 1147 Binary codes
    test
    Python标准库:内置函数reversed(seq)
    Matplotlib 工具包 使用教程索引
    6大设计原则(1):单一职责原则
    hdu 4104
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9643434.html
Copyright © 2011-2022 走看看