zoukankan      html  css  js  c++  java
  • kmp

    经过几天断断续续的思考,KMP总算是差不多搞懂了。

    主串s和模式串p进行匹配,p在s中出现的位置。

    代码如下:

    #include <cstdio>
    #include <iostream>
    using namespace std;
    const int N = 10001, M = 100001;
    char p[N], s[M];
    int ne[N];
    int main()
    {
        int n,m;
        cin>>n>>p+1>>m>>s+1;
        for(int i = 2, j = 0;i<=n;i++)
        {
            while(j && p[i] != p[j+1]) j = ne[j];
            if(p[i] == p[j+1]) j++;
            ne[i] = j;
        }
        
        for(int i = 1, j = 0;i<=m;i++)
        {
            while(j && s[i] != p[j+1]) j = ne[j];
            if(s[i] == p[j+1]) j++;
            if(j == n)
            {
                cout<<i-n<<" ";
                j = ne[j];
            }
        }
    }

    首先ne[i]代表模式串中以i为结尾前缀和后缀相等的长度。

    p字符串:a a c a a b

    ne[i]值: 0 1 0 1  2 0

    一位字母前后缀相等的长度为0,因为不能包括自身,所以从2开始。

    i = 2, j = 0; p[2] = p[1+1], j = 1; 所以p[2] = 1;

    j = 1, p[3] != p[1+1], j = ne[1] = 0; p[3] = 0;

    p[4] = p[0+1], j = 1; ne[4] = 1;

    p[5] = p[1+1], j = 2; ne[5] = 2;

    p[6] != p[3], j = ne[2] = 1, p[6] != p[2], j = ne[1] = 0. i = i + 1 = 7;

    模式串p以自己来不断的比较前缀后缀相等,采用双指针的方式,相等那么后移,不相等,那么j不停的前移。

    最后一次当j = 0, 虽然没有再进入那个while循环判断,但是在下面的if(p[i] == p[j+1])这里还是会比较了第一个字母,相同那么j = 1, 不相同j还是为0,j = 0;

    同样的,当匹配的时候,主串和模式串也是这样的不停的匹配的。

       1  2 3 4 5 6 7 8

    s: b a a c a a c a

    p:a a c a a b

    当i = 1, j = 0, a[i] != p[0+1]的时候,i自增下一次循环,j = 0;

    当s[2] = p[0+1], j ++;

    一直到s[7] != p[6], 这时候i = 7, j = 5,这时候就 j = ne[j] = ne[5] = 2;因为找到了前缀和后缀相等的长度,所以这时候p模式串就可以直接调过来,s[5] = p[1], s[6] = p[2],这是根据ne数组直接自动可以匹配的,这时候就只需比较:s[7] 与p[2+1],这里相等,所以j ++, i ++,继续往后比较,如果s[7] = d与p[3]不相等的话,那么j = ne[2] = 1, s[7] != p[2], j = ne[1] = 0,这时候跳出while循环,不要以为这里p[1] 和s[7]就不在进行比较了,实际上在下面的if(s[i] == p[j+1]) j++;这里实际上是再进行了一次比较的,如果相等, 那么下一次循环,j = 1, i++,比较的就是s[8] 和p[2]了。如果不相等的话,那么下一次比较就是s[8]和p[1],即从模式串p的第一个字母进行比较。

    综上,如果模式串p的前后缀相等的长度越长即ne[]越大,跟s已经匹配的越多的话,那么即使当下一次s[i++] != p[j+1]的话,那么这时也不需要像双重枚举暴力那样,j 从头开始,i回到第一个匹配位置的下一个,如果上面越长,越大,实际上浪费了很多已有的资源空间。i没必要退回,j退回,而且还是通过ne数组来跳跃性的退回,比一位一位笨拙的退回效率高很多。j = n,说明已经匹配完了,因为p[n-1+1] = s[i], j++,这里是先比较匹配,再自增,从1开始的话,那么就是i - n。

  • 相关阅读:
    Oracle触发器用法及介绍
    连接mysql用mysql_connect不能连接
    中标麒麟上安装配置达梦数据库7
    (转)全局变量和局部变量区别
    DSP编程与调试总结
    SERCOS总线程序相关
    C编程小结1
    C语言编程的一些小总结
    【转】#define 定义别名和 typedef 声明类型的区别
    DSP开发程序相关问题总结
  • 原文地址:https://www.cnblogs.com/longxue1991/p/12684719.html
Copyright © 2011-2022 走看看