KMP算法详解+大牛是如何想到KMP算法的?

我们的目标是将模式串与待匹配串进行匹配,看模式串是否在待匹配的串之中,先来看传统的BF算法

1.   BF算法:

模式串

a

b

a

b

a

c

b

i

 

 

 

 

 

 

待匹配串

a

b

a

b

a

b

a

a

b

a

b

a

c

b

j

 

 

 

 

 

 

 

 

 

 

 

 

 

模式串用p(n)表示,设定指针i表示当前正在进行匹配的字符;源串用T(m)表示,用指针j表示当前正在匹配的字符。于是,若p(i)=T(j),则i++,j++;对于上例,当i和j运行到红色区域时,出现了第一次不匹配的情况,也就是说若p(i)!=T(j),此时需要进行源串的回溯。那么回溯到哪个地方呢?那么由于此时已经和模式串中的已经匹配了i-1个串,所以回退i-1个字符,故此时指针的更新应该是:i=1,j=j-i+1;如此往复,直到i==n表示已经识别出来,或者j==m表示源串已经识别完毕。

 

对此算法的优化分析:该算法复杂度略高的原因是,每当出现一个不匹配的情况,就要回溯所有已经识别的模式串中的字符,而实际上,前面已经比较过,回溯意味着计算的重复。对于本例中的情况,显然模式串向右滑动一个,不能匹配;向右滑动两个,可以匹配到红色字符串,也就是说:若知道已经匹配的串中,最长的真前缀(这个前缀还是已经匹配 串的后缀)是什么,就能很大地简化计算:最长真前缀不用回溯重复计算。通关观察这个算法,我们发现对模式串的识别过程,已经蕴含了相当多的信息,如果直接采用BF回溯的方法,这些信息就没有有效利用,所以应该将模式串中蕴含的信息存储起来,供给下一次匹配继续使用。借助这种思想,提出KMP算法:

 

2.   KMP算法

先看一下,为了优化上述算法,我们需要做的关键工作:

 

a

b

a

b

a

c

b

 

 

 

 

 

 

i

 

 

 

a

b

a

b

a

b

a

a

b

a

b

a

c

b

 

 

 

 

 

 

J

 

 

 

 

 

 

 

 

此时,p(i)与s(j)不再匹配,但是蓝色部分却是匹配的,而且这一部分只是和模式串有关系,那么如何描述这个蓝色子串的性质呢?它是:使得b1b2···bfs是最长的即使b1b2···bs的真前缀,又是b1b2···bs的后最的子串。因此,KMP算法有两个部分,第一是求解f(s)函数;第二是利用此函数进行模式匹配。

(1)    求解f(s)函数

失效函数的计算,失效函数是针对于模式串而言的。

给出几个例子:

1

a

b

a

b

a

a

b

a

0

0

1

2

3

1

2

3

2

a

b

a

b

a

b

b

a

0

0

1

2

3

4

0

1

3

a

b

b

a

a

b

b

a

0

0

0

1

1

2

3

4

4

a

b

a

b

a

c

b

 

0

0

1

2

3

0

0

 

我们最先想到的往往是蛮力法:利用子串进行匹配,若成功,则停止;反之,将子串长度减一,再进行匹配;重复上述过程即可。例如,求上表中的f(5)的时候,先看abab是否满足,不满足,于是用aba,满足,于是最长就是aba,长度为3。求解f(6)的时候,同样采用蛮力试探的方法,但这个比较费时,最长算的f(6)等于1。我们当然知道,即使这样,在模式串长度很小,源串长度很大的时候依然可以减少时间开销,但是还有没有继续优化的空间呢?

 

注意到:在第一个串中,算得f(4)=2,此时b3=b5,所以很显然f(5)等于2+1=3;会不会f(5)>3呢?用反证法:加入f(5)>3,那么f(4)>2,与前面矛盾。也就是说,在计算f(s)的时候,如果bs=bf(s-1)+1那么,直接可以推到得到bs=bf(s-1)+1.但是如果

bs=bf(s-1)+1不成立呢?这时就相当于是计算f(6)的情况。此时,实际上我们要找的是子串的子串,而这个已经有了计算结果,所以可以找到。再比较下一个元素是否相等,相当则找到,反之,继续重复上述过程。写成程序如下:(注意下面的程序的当前变量是b【s+1】)

t=0;

f(1)=0

for(s=1;s<n,s++)

{

       while(t>0&&b[s+1]!=b[t+1]) t=f(t);

       if(b[s+1]==b[t+1])

        {

        t++;

        f(s+1)=t;

        }

}

(2)    模式匹配

现在已知模式串p(n)和失效函数f(n),求解是否有其中有匹配的模式串,如果有,返回模式串匹配的位置,,其中算法的关键之处在于

S=0;

For(i=0;i<m;i++)

{

   While(s>0&&a[i]!=b[s+1])s=f[s];

 If(a[i]==b[s+1])s++;

If(s==n) return true;

}

Return false

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值