KMP 算法(Knuth–Morris–Pratt algorithm)

kmp 算法是模式匹配比较高效的一种算法。所谓模式匹配是指对应两个字符串s1和s2,s1在s2完全匹配的位置,其中s1称为模式串,s2称为主串。例如s1 = abc, s2 = abababc, 两者匹配的位置为:

既然找到问题的内容,接下来就是分析如何解决问题了,首先想到的一般都是暴力:将两个字符串从头开始匹配,如果遇到不匹配的字符则从主串的下一个字符开始匹配,例如:
1-1
1
1-2
2
dot dot dot dot dot….==============>>>>>>
1-3
3

1-4
4
dot dot dot …==============>>>>>
1-5
这里写图片描述

就这样一直搜索下去,直到完全匹配:
1-6

这个算法虽然可行,但是效率太低,因为每次都要把搜索过的串从新比较一次,复杂度达到O(n*m),如果两个串都很长的话,耗时就突破天际了。
如果仔细观察一下,其实可以发现图1-4~1-5之间这些步骤都是可以省略的,因为模式串的前部分子串都没有跟主串匹配,比较了也没意思啊。那么就可以想办法将模式串平移到适当的位置上,就可以省去一些步骤(事实证明这个省去极大地提高了匹配的效率。)。
于是,Knuth,Morris和Pratt通过研究发现(我也不知道怎么发现的= =),可以通过一个部分匹配的表(也称为next数组)来作为平移量的计算。对于一个模式串,next数组的值是这样的:
7
怎么确定next数组的数值呢?可以这样想:为什么有些串可以跳过而有些串不能跳过?因为模式串的前部分子串没有跟其匹配,那就可以直接跳到可以匹配的串那里,比如:

======>>>>>>有这么一条公式:平移数 = 已匹配数 - 匹配数对应的next[i]值,例如此处匹配数为6,最多匹配到”B”,”B”对应的值为2,平移数 = 6 - 2 = 4。

那么就可以看到,平移的位置其实是跟模式串的格式相关的,next数组的计算其实是前缀后缀的最大公共字符数(前缀不能包含最后一个字符),例如 “aba”的前缀为”a”, 后缀为 “a”,最长为1,而 “abc”是没有公共长度的。
注意next数组的每一个元素有:
(0)”A” 没有公共长度,因而为0
(1)”AB” 同上
(2)”ABC”同上
(3)”ABCD” 同上
(4)”ABCDA” 最长公共为”A”,长度为1
(5)”ABCDAB” 最长公共为”AB”,长度为2
(6)”ABCDABD” 没有公共长度,为0
然后就blablabla都可以算出来了。
附上wikipedia的伪代码:
kmp算法:

next数组计算(虽然人家是把没有公共长度设为-1,有一个长度则设为0…anyway,plus one and we are the same….):

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值