• KMP 和 扩展KMP


    KMP:在主串S中找子串T的位置KMP算法的时间复杂度O(|S|+|T|)。

    #define maxn 1000
    char s[maxn],t[maxn];//s为主串,t为子串
    int net[maxn],l1,l2;//l1为主串长度,l2为子串长度
    void get_next() {
        int i=0,j=-1;
        net[0]=-1;
        while(i<l2) {
            if (j==-1 ||t[i]==t[j])
            {
                ++i,++j;
                if (t[i]!=t[j]) net[i]=j; //优化next数组
                else net[i]=net[j];
            }
            else j=net[j];
        }
        /*for (i=0;i<l2;i++)
            printf("next[%d]=%d
    ",i,next[i]);  */
    }
    //返回子串在主串第pos个字符之后的位置
    //若不存在则返回0
    int KMP(int pos)
    {
        int i=pos,j=0;
        get_next();       //核心部分
        while(i<l1&&j<l2) {
            if (j==-1||s[i]==t[j]) i++,j++;
            else j=net[j];
        }
        if (j==l2) return i-l2;
        else return 0;
    }
    1
    void getNext() {
        Next[1] = 0;
        for (int i = 2, j = 0; i <= n; i++) {
            while(j > 0 && a[i] != a[j+1]) j = Next[j];
            if (a[i] == a[j+1]) j++;
            Next[i] = j;
        } 
    }
    void KMP() {
        for (int i = 1, j = 0; i <= m; i++) {
            while(j > 0 && (j == n || b[i] != a[j+1])) 
                j = Next[j]; 
            if (b[i] == a[j+1]) j++;
            f[i] = j;
            // if (f[i] == n) 此时是A在B中的某一次出现
        }
    }
    2(来着算法竞赛进阶指南)

    扩展KMP: 

    给定串S,和串T,设S的长度为n,T的长度为m,求T与S的每一个后缀(包括S)的最长公共前缀。复杂度为O(n+m)。

    设extend数组,extend[i]表示T与S[i,n-1]的最长公共前缀,要求出所有extend[i](0<=i<n)。

    注意到,如果有一个位置extend[i]=m,则表示T在S中出现,而且是在位置i出现,这就是标准的KMP问题,所以说拓展kmp是对KMP算法的扩展,所以一般将它称为扩展KMP算法。

    详细过程参考博客: https://blog.csdn.net/qq_40160605/article/details/80407554

              https://blog.csdn.net/dyx404514/article/details/41831947

    const int K=1000005;
    int nt[K],extand[K];
    char S[K];
    void Getnext(char *T,int *next)
    {
        int len=strlen(T),a=0;
        next[0]=len;
        while(a<len-1 && T[a]==T[a+1]) a++;
        next[1]=a;
        a=1;
        for(int k=2; k<len; k++)
        {
            int p=a+next[a]-1,L=next[k-a];
            if( (k-1)+L >= p)
            {
                int j = (p-k+1)>0 ? (p-k+1) : 0;
                while(k+j<len && T[k+j]==T[j]) j++;
                next[k]=j;
                a=k;
            }
            else next[k]=L;
        }
    }
    void GetExtand(char *S,char *T,int *next)
    {
        Getnext(T,next);
        int slen=strlen(S),tlen=strlen(T),a=0;
        int MinLen = slen < tlen ? slen : tlen;
        while(a<MinLen && S[a]==T[a]) a++;
        extand[0]=a;
        a=0;
        for(int k=1; k<slen; k++)
        {
            int p=a+extand[a]-1, L=next[k-a];
            if( (k-1)+L >= p)
            {
                int j= (p-k+1) > 0 ? (p-k+1) : 0;
                while(k+j<slen && j<tlen && S[k+j]==T[j]) j++;
                extand[k]=j;
                a=k;
            }
            else extand[k]=L;
        }
    }
    int main()
    {
        while(scanf("%s%s",S,T)==2)
        {
            GetExtand(S,T,nt); 
            for(int i=0; i<strlen(T); i++)
                printf("%d ",nt[i]);
            puts("");
            for(int i=0; i<strlen(S); i++)
                printf("%d ",extand[i]);
            puts("");
        }
        return 0;
    }
    扩展KMP
  • 相关阅读:
    POJ 1330 Nearest Common Ancestors(LCA Tarjan算法)
    LCA 最近公共祖先 (模板)
    线段树,最大值查询位置
    带权并查集
    转负二进制
    UVA 11437 Triangle Fun
    UVA 11488 Hyper Prefix Sets (字典树)
    UVALive 3295 Counting Triangles
    POJ 2752 Seek the Name, Seek the Fame (KMP)
    UVA 11584 Partitioning by Palindromes (字符串区间dp)
  • 原文地址:https://www.cnblogs.com/l999q/p/11304900.html
Copyright © 2020-2023  润新知