码迷,mamicode.com
首页 > 其他好文 > 详细

kmp

时间:2020-04-12 14:09:23      阅读:57      评论:0      收藏:0      [点我收藏+]

标签:stream   就是   pre   iostream   i++   ++   包括   不能   int   

经过几天断断续续的思考,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。

 

kmp

标签:stream   就是   pre   iostream   i++   ++   包括   不能   int   

原文地址:https://www.cnblogs.com/longxue1991/p/12684719.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!