模式匹配KMP算法

看了好几遍模式匹配kmp算法,始终没有看明白,今天总算有些头绪了,写下来。(ps:用的是严蔚敏的数据结构,感觉这本书还不错)

1.普通的模式匹配

这里先简单地说一下普通模式匹配算法的思想,不做过多的解释。
例如:

主串 a b c a b a b c c c a b c a b d
模式串 a b c a b d

主串中的第i个字符与模式串中的第一个字符进行比较,如果相同则继续比较下一个字符,如果不同,主串从i+1个字符开始,和模式串做匹配,直到所有字符全部匹配上结束。
这个算法容易理解但是效率比较低,在上例中第一次匹配时abcab已经匹配,那可不可以根据现有的信息,向右尽可能多的移动模式串进行下一次的匹配呢?答案是可以的,于是有了KMP算法。

2.KMP算法

我们可以看出上例中第一次匹配失败的时候主串c应该和模式串中的a进行下一次的比较。但是计算机应该怎么知道呢?先解决这个问题。
当主串中第i个字符和模式串中第j个字符匹配失败的时候,主串中的第i个字符应该与模式串中哪个字符进行比较?
讨论一般情况,设:

主 串: ’ s1 s2 s3 s4 … si si+1 si+2 … sn’
模式串:’p1 p2 ….pj pj+1 pj+2 ….pm’

假设此时应该讲模式串回溯到pk位置和主串进行比较,则在pk之前的字符和主串一定是匹配的。
如图所示
图1

这里写图片描述
图2

图2中k之前的部分满足:

‘p1 p2 p3 …pk-1’ = ‘si-k+1 sI-k+2 … si-1’

图1中已匹配的部分满足:

‘pj-k+1 pj-k+2 ….pj-1’ = ‘si-k+1 si-k+2 … si-1’

由上面两个式子可以得出:

‘p1 p2 … pk-1’ = ‘pj-k+1 pj-j+2 … pj-1’

如果模式串中存在满足上式的两个子串,则当主串中i和模式串中j不相等时,将模式串向右移动至k与i对齐,进行下面的匹配。
下面用一个next[]数组记录模式串中每个字符不匹配是需回溯的k点。
这里写图片描述

下面解释一下’p1 p2 … pk-1’ = ‘pj-k+1 pj-j+2 … pj-1’这个式子怎么找max值

设一个模式串为:

a b a a b c 并假设字符串编号从1开始

‘p1 p2 … pk-1’ 这个式子 下面以“左式”代替
‘pj-k+1 pj-j+2 … pj-1’这个式子 下面以“右式”代替
j = 1 时 next[1] = 0
j = 2 时 k 只能取1 容易看出next[2] = 1
j = 3 时 k 取 1 没有子串,(以后不再讨论这种情况)
………….k 取 2 时:左式为 p1=a 右式为p3-2+1=a 所以k=2时成立,此时next[3] = 2
j = 4 时 k 取 2 时:左式为p1=a 右式为p4-2+1=a 所以k=2时成立
………….k 取 3 时:左式为p1p2=ab 右式为p4-3+1 p4-3+2=ba 所以k=3时不成立,此时next[4] = 2
以此类推。

在网上看到另一种比较简单的算法(来自阮一峰的网络日志):
原文地址:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

这里写图片描述

仍然拿 a b a a b c 举例
a 的前缀后缀为空集,
ab 前缀为a 后缀为b, 最长的相等子集长度为0
aba前缀为 a ab 后缀为ba a 最长的相等子集长度为1
abaa前缀为a ab aba 后缀为baa aa a最长的相等子集长度为1
abaab前缀为a ab aba abaa 后缀为 baab aab ab b 最长的相等子集长度为2
abaabc前缀为a ab aba abaa abaab 后缀 baabc aabc abc bc c最长的相等子集长度为0
得到的部分匹配值为:0 0 1 1 3 0
移动位数 = 已匹配的字符数 - 对应的部分匹配值

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值