• KMP


    KMP学了好几遍了,今天才明白的差不多...

    留篇博客,免得自己以后忘了qaq

    我们先讨论next的含义:

    next[i] : 在0<=j<i中的最大的j,满足0-i中,使长度为j的后缀和长度为j的前缀相同

    接下来我们讨论两个问题:1.怎么求next; 2.有了next怎么求匹配

    定义:next[1] = 0(由定义),next[0]不定义,默认为0

    问题1:怎么求next

    考虑目前到i + 1,令j=next[i],那么如果a[j + 1] != a[i + 1],说明此时的next[i]的下一位与a[i + 1]不等,即next[i + 1] != next[i] + 1了

    那么和0-i的这一段后缀相等的最大前缀只能是next[j]即next[next[i]],那么令j=next[j],继续进行上述判断,直到j=0无法判断为止

    问题2:有了next怎么求匹配

    考虑目前匹配到模版串的j,原串的i,如果a[j] == a[i],自然这一位相等,令j++

    否则,已经匹配的一段j中,有一部分和原串之前匹配的部分是相等的,这个位置就是next[j](显然的由next的定义,这个长度是合法且极大的)

    这样问题就可以解决了

    考虑kmp的复杂度,在问题2中,我们至多只令j增加n次,而虽然在令j=next[j]的过程中可能有多次运算,但可以通过势能分析证明

    我们将j=next[j]的复杂度摊到每次j++,那么每次操作平均复杂度至多是2,总复杂度O(n+m)

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int maxn=1e7+1;
    int next[maxn],j=0;
    char s1[maxn],s2[maxn];
    int main()
    {
        scanf("%s",s1+1);
        scanf("%s",s2+1);
        int len1=strlen(s1+1),len2=strlen(s2+1);
        //cout<<len1<<" "<<len2;
        for(int i=2;i<=len2;i++)
        {
            while(j&&s2[i]!=s2[j+1]) j=next[j];
            if(s2[i]==s2[j+1]) j++;
            next[i]=j;
        }
        j=0;
        for(int i=1;i<=len1;i++)
        {
            while(j&&s1[i]!=s2[j+1]) j=next[j];
            if(s1[i]==s2[j+1]) j++;
            if(j==len2) 
            {
                printf("%d
    ",i-len2+1);
                j=next[j];
            }
            //cout<<"hahha"<<endl;
        }
        for(int i=1;i<=len2;i++) printf("%d ",next[i]);
    }
    View Code
  • 相关阅读:
    2018前端越来越流行的的技术
    程序员怎么写出一份漂亮的简历
    程序员怎么写出一份漂亮的简历
    程序员如何利用空闲时间挣零花钱
    扫雷(mine)
    一道数论好题(math)
    消失的数字(number)
    1380 没有上司的舞会 40分
    2596 售货员的难题 水深搜
    JavaEE Tutorials (17)
  • 原文地址:https://www.cnblogs.com/LM-LBG/p/10801925.html
Copyright © 2020-2023  润新知