(如果您已经了解过KMP算法的请跳过这一段)刚刚进来的童鞋可能还不明白什么是KMP算法,现在在这里先大体的说以下,KMP算法其实就是字符串匹配的算法,和C语言的一个函数strstr();功能一样,引用严蔚敏教授的例子,主串 S:acabaabaabcacaabc 模式串 T:abaabcac。用T去匹配S,返回T串在S串中的位置。对于这个问题,很容易想到常规的匹配方法,T串匹配每一个S串的位置都匹配一次(这里就不具体说明,大家一定都很容易想到)。但是这种算法在最坏情况下的时间复杂程度是O(n*m) n、m是两个字符串的串长。接下来我要介绍D.E.Knuth 与 V.R.Pratt 和 J.H.Morris 同时发现的,我们称KMP算法,其时间复杂程度是O(n+m)。
KMP算法和常规算法不同的就是指针回朔的问题,还是用一个例子说明这个问题。
S:a c a b a a b a a b c a c a a b c
T:a b a a b c a c
N:0 1 1 2 2 3 1 2 <-- next[1..8]
第一趟:
指针 i = 1 –> i = 2
S:a c a b a a b a a b c a c a a b c
T:a b a a b c a c
指针 j = 1 –> j = 2
j = 2的时候不匹配,next[2] = 1,j指针回朔到1
第二趟:
指针 i = 2
S:a c a b a a b a a b c a c a a b c
T: a b a a b c a c
指针 j = 1
j = 1的时候不匹配,next[1] = 0,i、j同时加1
第三趟:
指针 i = 3 –> i = 8
S:a c a b a a b a a b c a c a a b c
T: a b a a b c a c
指针 j = 1 –> j = 6
j = 6 时候不匹配,next[6] = 3,j指针回朔到3
第四趟:
指针 i = 8 –> i = 14
S:a c a b a a b a a b c a c a a b c
T: a b a a b c a c
指针 j = 3 –> j = 9
j走到末尾,匹配完成!
看到这里,相信大多是人都有点糊涂了,没关系,听我慢慢说,我们先分析一个这个匹配过程,从上面看,KMP算法在这个例子上只走了4 趟,如果是常规方法,要6趟才能完成。KMP算法中,还有一个非常非常重要的就是i 指针不回朔,下面将详细讲解是如何实现的。
要做到i指针不回朔,我们还的先对T串进行一下预处理,这里,我们引入一个next函数(计算公式如图1),这个函数值记录的是当匹配出现字符串不相等的时候,i指针不回朔,j指针回朔的位置,也就相当于让T串向右滑动一定的距离后,继续比较。现在对照next值,再重新看一遍是不是稍稍明白了一点了呢?
看到这里,你的脑子里一定在问,为什么next函数可以跳过这么多不需要的匹配过程呢?这个其实就就是KMP的核心所在,我也是困扰在这上面一个星期之久。KMP算法用了一个非常非常简单的原理,比如,已知字符A B C: ( A != B && A == C ) ==> B != C 。很容易理解吧。
接下来我将详细介绍如何利用上面的那条性质进行字符串匹配,还是举上面的例子:
S:a c a b a a b a a b c a c a a b c
T: a b a a b c a c
当出现不匹配的时候,我们让 j 指针回朔到第一个a b后面,因为 c 前面 a b 等于 最前面的 a b,next函数保存的就是满足T[1..n] == T[j-1-n] n最大时 next[j] = n + 1 。
指针回朔后变成这个样子:
S:a c a b a a b a a b c a c a a b c
T: a b a a b c a c
到现在为止,如果你大致明白KMP的原理和比较过程,那么我5个小时的工作还算有些成果。根据上面的过程,我们很容易写出KMP算法的主函数,下面给出C代码(注意C语言字符串下标从0开始):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
上面的代码是在知道next函数的基础上的,我们怎么求next的函数呢?
计算方法如上面图1所示,下面先给出代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
说实话这段代码我也纠结了很久,最后还是被严蔚敏教授一语惊醒梦中人,计算next的值是递推的过程!分析如下:
已知:next[0] = -1;
假设:next[j] = k; 又 T[j] = T[k];
推出:next[j + 1] = k + 1 ;
或者
已知:next[0] = -1;
假设:next[j] = k; 又 T[j] != T[k];
推出:k = next[j] ;
循环上面的过程。