• KMP算法初步学习


    准备系统的学习一下算法,就先行KMP开始吧!

    到目前为止,我能用到KMP的地方有三类题目:
    - 给出主串s和模式串t,查找t在s中出现的位置
    - 给出主串s和模式串t,查找t在s中出现的次数
    - 给出一个字符串t,求t中循环节的个数

    KMP算法的时间复杂度是O(n),因为主串s在匹配过程中是不回溯的,KMP算法的巧妙之处在于对模式串的预处理,当模式串的第j个位置与主串第i个位置不匹配的时候,他会回溯到next[j]位置,继续与i匹配,next[]数组就是预处理的失配函数,记录失配时模式串要回溯到的位置。

    更加详细的解释网上也有很多详细的资料,这里给出几道基础的题目练练手!

    题目: hdu 1711
    题意:找出模式串在主串中首次出现的位置

    #include<cstdio>
    const int N=1e6+5;
    int s[N],t[N],slen,tlen;
    int next[N];
    void getNext()
    {
        int j,k;
        j=0;k=next[0]=-1;
        while(j<tlen){
            if(k==-1||t[j]==t[k])next[++j]=++k;
            else k=next[k];
        }
    }
    int KMP_Index()
    {
        getNext();
        int i,j=0;
        for( i=0;i<slen&&j<tlen;i++){
            while(j&&s[i]!=t[j])j=next[j];
            if(s[i]==t[j])j++;
        }
        if(j==tlen)return i-tlen+1;
        return -1;
    }
    int main()
    {
        int T;
        //freopen("f.txt","r",stdin);
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&slen,&tlen);
            for(int i=0;i<slen;i++)scanf("%d",&s[i]);
            for(int i=0;i<tlen;i++)scanf("%d",&t[i]);
            printf("%d
    ",KMP_Index());
        }
        return 0;
    }

    题目:poj 3461
    题意:统计模式串在主串中出现的次数

    #include<cstdio>
    #include<cstring>
    const int N=1e6+5;
    char s[N],t[N];
    int next[N],slen,tlen;
    void getNext()
    {
        int i,j;
        i=0;j=next[0]=-1;
        while(i<tlen){
            if(j==-1||t[i]==t[j])next[++i]=++j;
            else j=next[j];
        }
    }
    int KMP_Count()
    {
        getNext();
        int ans=0;
        int j=0;
        for(int i=0;i<slen;i++){
            while(j&&s[i]!=t[j])j=next[j];
            if(s[i]==t[j])j++;
            if(j==tlen){
                ans++;
                j=next[j];
            }
        }
        return ans;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--){
            scanf("%s%s",t,s);
            tlen=strlen(t);
            slen=strlen(s);
            printf("%d
    ",KMP_Count());
        }
    }

    题目:poj 1961
    题意:给一个字符串,找出其中循环节的位置和个数
    分析:
    这题考察对next数组的理解,next数组记录的是不匹配时要回溯到的位置,例如,当第n个位置不匹配时,要回溯到next[n],中间跳过了t=n-next[n]个数,t就是最小循环节的个数(如果是周期串的话)因为他不匹配了,n之前的t个数与next[n]之前的t个数是匹配的。为什么?因为next数组记录的位置前面肯定是匹配的,这是由next数组的定义决定的。

    #include<cstdio>
    const int N=1e6+6;
    char s[N];
    int next[N],slen;
    void getNext()
    {
        int i,j;
        i=0;j=next[0]=-1;
        while(i<slen){
            if(j==-1||s[i]==s[j])next[++i]=++j;
            else j=next[j];
        }
    }
    int main()
    {
        int cas=0;
        while(~scanf("%d",&slen)&&slen){
            scanf("%s",s);
            getNext();
            printf("Test case #%d
    ",++cas);
            for(int i=1;i<=slen;i++){
                if(i%(i-next[i])==0&&next[i])
                    printf("%d %d
    ",i,i/(i-next[i]));
            }
            for(int i=0;i<=slen;i++)
                printf("%d ",next[i]);
            printf("
    ");
        }
    }
  • 相关阅读:
    vue 路由的实现 hash模式 和 history模式
    标准规范
    知识产权、项目收尾
    合同法、著作权、实施条例
    招投标法、政府采购法
    项目成熟度模型、量化项目管理
    信息系统综合测试与管理
    信息系统安全管理
    Spring Boot 6. 与数据访问
    Spring Boot 5. 与Docker
  • 原文地址:https://www.cnblogs.com/01world/p/5651264.html
Copyright © 2020-2023  润新知