最近在学习kmp算法,想了很久,终于于前日想通。
首先要说明,学习过程中主要参考了如下两篇文章:
- 这篇文章的讲解过程非常清晰 但是代码应该VB http://www.matrix67.com/blog/archives/115/
- 这篇文章的代码不错 http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html
kmp算法有几个关键的点 想通了就没什么了。(下面例子中,我们要匹配mod串是否出现在str串中)
1. 按照正常的字符串匹配,如果到某个位置的字符不匹配的时候,str串会回退(回到本次匹配开始位置的下一个位置),而mod串会回到起始位置,这样就会增加时间复杂度。但是在kmp算法中若遇到不匹配,str串不会回退,而mod串也不一定回退到起始位置。这样在时间复杂度上就大大增加了。
2. next数组(由getNext函数填充该数组)。遇到某个字符不匹配时,str串留在原地,mod串到底退回到什么位置就由next决定。
0 1 2 3 4 5 6 7 8
a b a b a b a a b
a b a b a c
a b a b a c 回退后的mod串
0 1 2 3 4 5
当str[5] != mod[5]时,看一下前面,mod[0]一直到mod[4]都是匹配的,只要找到“ababa”这个字符串的前缀与后缀相当的最长 子串,就能找到mod回退到什么位置,当前我们找到的最长子串是“aba”,那么下一次的匹配就从mod[3]也就是最长子串(前缀)的下一位开始进行比较,因为前缀与后缀相等,所以mod[0],mod[1],mod[2]刚好可以替代原来位置的的mod[2],mod[3],mod[4],而匹配也将从mod[3]开始。
3. getNext函数的思路,首先将数组填充为0。
0 1 2 3 4
a b a b c
(1) mod[0]与mod[1]比较,不相等
(2)mod[0]与mod[2]比较,相等next[2] = 1,这就是说在“aba”这个字符串的前缀与后缀相等的最长子串是“a”,而next[2]记录的是这个最长子串(前缀)的下一个位置(即“b”的位置)
(3)mod[1]与mod[3]比较,相等next[3] = 2,同上,在“abab”串中,最长子串是“ab”,next[3]记录的是最长子串(前缀)的下一个位置
(4)mod[2]与mod[4]比较,不相等,如果继续比较,下次是mod[0]与mod[5]进行比较