KMP算法
[编程语言教程]

注明:参考文献《信息学奥赛一本通》

———————————————————————————————————————“my name is the porter of nature”

介绍

KMP算法是用于字符串匹配问题的,它利用一种巧妙而又不失逻辑的方法去减少算法的时间复杂度,在处

理较多数据匹配时或者数据范围大的时候用处极大(反正我是五体投地),也就是如果问主串是否包含子

串的问题可以大幅度让你开心得飞起…

举个栗子 :我们有一个主串— A=”aaaaaaaaaaaaaaaaab” 和 子串— B=“aaab”,如果我们要找从A串中哪

一个位置起开始匹配,通常是枚举位置后验证匹配,那么它的时间复杂度为O(n*m)[n为A串长,b为B串长]

,最坏情况下这通常不能接受,大大的TLE就给你奉上;而KMP算法即使是最坏情况,它也可以满足O(n)的

时间复杂度。

概念

首先我们明确几个概念。。。

A=”aaaaaaaaaaaaaaaaab”    B=“aaab”

~主串(母串)——即等待匹配的A串

~模式串——即用来匹配的B串

 

流程

假设我们现在有一个主串A=“abababaabab”和一个模式串B=“ababacb”,我们用实例去表示这个过程:

 

我们现在匹配到i=j=5时,此时前面的都可以匹配,但是A[6]!=B[6].

i= 1 2 3 4 5 6 7 8 9

    a b a b a b a a b a b …          (主串)

    a b a b a c b                          (模式串)

j= 1 2 3 4 5 6 7

 

于是我们就用你聪明的小脑瓜子想一下,我们现在应该将j改成更小的j’,使得j‘前面的字母可以满足刚好

和A串前面的匹配,然后继续匹配下去。这个时候我们可以发现,B串中前面j’个字母和末尾的j‘个字母

要完全相同,这样才能移动B串,如下面所示:

i= 1 2 3 4 5 6 7 8 9 …

    a b a b a b a a b a b …          (主串)

          a b a b a c b                    (模式串)

j=       1 2 3 4 5 6 7


这样的话我们就可让A[6]=B[4]了,即可以继续匹配下去。我们也可以得知,新的j的取值与i是没有关系

的,它就是一个B串起点在疯狂跳跃的过程,逆向思考的话,就是在前面的j对应的字母不能匹配的话,

就缩小j,使得B串能够跳跃去继续匹配罢了,,

那么我们可以预处理一个数组P[j]去处理,即它表示B组与A组匹配到B组第j个字母,第j+1个字母不能

匹配时,新的j最大可以是多少。则P[j]满足B[1……k] = B[j-k+1……j]。(好好消化一下再继续看)

 

此时我们继续匹配下去,则有:

i= 1 2 3 4 5 6 7 8 9 …

    a b a b a b a a b a b …          (主串)

          a b a b a c b                    (模式串)

j=       1 2 3 4 5 6 7

这时又出现A[7+1]!=B[5+1],我们就让B开始跳起来,因为新的 j = P[5] = 3;(P的求法后续再讲)

i= 1 2 3 4 5 6 7 8 9 …

    a b a b a b a a b a b …          (主串)

                a b a b a c b              (模式串)

j=             1 2 3 4 5 6 7

 但是a != b ,所以我们 继续 j = P[3] = 1;

i= 1 2 3 4 5 6 7 8 9 …

    a b a b a b a a b a b …          (主串)

                      a b a b a c b       (模式串)

j=                   1 2 3 4 5 6 7

依旧是不满足,那就 j = P[1] = 0了,它已经没力气了~~

i= 1 2 3 4 5 6 7 8 9 …

    a b a b a b a a b a b …          (主串)

                         a b a b a c b     (模式串)

j=                   0 1 2 3 4 5 6 7

所以我们只有j==m的时候,我们才可以匹配完全…但也存在后续匹配不了滴~

先打这个匹配过程的代码?

//实际操作中字符串数组以0开头,所以上面从1开始是指从第1个位置开始
j=0; 
for(i=0;i<sA.length();i++){
    while(j>0 && sB[j+1]!=sA[i+1]) j=P[j];
    //即不能继续匹配下去,且还没到没力气的时候,就继续减小j
    if(sB[j+1]==sA[i+1]) j++; 
    //此时可以继续匹配,那就匹配下去
    if(j==m) {
    printf("%ld ",i+1-m+1);// 子串在母串的位置 ,当然是第几个位置喽
    j=p[j];   //开启新征程
    }
}
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » KMP算法