Lec2-KMP算法学习
之前上数据结构课时没有学到,现在补起来。
Ref:严蔚敏版《数据结构》上的讲解(浅显易懂)
http://www.ics.uci.edu/~eppstein/161/960227.html
子串的定位操作Index(S,T,pos)通常称作串的模式匹配(其中T称为模式串)。传统的字符串匹配算法如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
| b | a | n | a | n | a | n | o | b | a | n | o |
index=0 | X |
|
|
|
|
|
|
|
|
|
|
|
index=1 |
| X |
|
|
|
|
|
|
|
|
|
|
index=2 |
|
| n | a | n | X |
|
|
|
|
|
|
index=3 |
|
|
| X |
|
|
|
|
|
|
|
|
index=4 |
|
|
|
| n | a | n | o |
|
|
|
|
index=5 |
|
|
|
|
| X |
|
|
|
|
|
|
index=6 |
|
|
|
|
|
| n | X |
|
|
|
|
index=7 |
|
|
|
|
|
|
| X |
|
|
|
|
index=8 |
|
|
|
|
|
|
|
| X |
|
|
|
index=9 |
|
|
|
|
|
|
|
|
| X |
|
|
index=10 |
|
|
|
|
|
|
|
|
|
| n | X |
index=11 |
|
|
|
|
|
|
|
|
|
|
| X |
KMP算法可以将传统字符串匹配算法的复杂度(O(m*n))提升到O(m+n),其中n为target(主串)的长度,m为 pattern(子串)的长度。空间复杂度为O(m)。
1.KMP的原理
其改进在于,每当一趟匹配过程中出现字符比较不等时,不需回溯 i 指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。
2. next函数
next函数给出了在比较到当前字符时,如果不匹配,前面的字符应相当于已经比较过的位数。
当匹配过程中出现不相等时,如果不要回溯指针,而是从此位开始继续比较,则需要next函数来知指明要和模式串(子串)的哪一位进行比较。
例如对于模式串acae,next(4)=2. 即当第四位匹配失败时,一定满足... ak-3 ak-2 ak-1 = a1 a2 a3 ...(字符串下标从1开始)
而acae,满足a(2)=a(0) ,则next(3)=1;若为abcd,则next(3)=0,表示从子串的第一个a开始比较。(所有下标包括next函数均从1开始标号)
a c a a c a e
| | | !
a c a e
|->遇到不匹配(a!=e),从不匹配位继续比较,设当前母串标号为k,子串标号为j,当满足ak-i... ak-2 ak-1 = a1 a2 a3 ...ai时,next(j)=i。而ak-i... ak-2 ak-1 ak-1 一定是母串和子串的已匹配部分,故aj-i... aj-2 aj-1 aj-1 = ak-i... ak-2 ak-1 ak-1
此例中则有next(4)=2.
3. next函数的计算
KMP算法是在已知模式串的next函数的基础上执行的,那么,如何求得模式串的next函数值呢?
从上述讨论可见,此函数值仅取决于模式串本身而和相匹配的主串无关。我们可以从分析其地你故意出发用递推的方法求得next函数值。
由定义得知
next[1]=0
设next[j]=k,这表明在模式串中存在下列关系:
‘p1...pk-1' = 'pj-k+1...pj-1'
其中k为满足1<k<j的某个值,并且不可能存在k'>k满足此等式。此时next[j+1]=?可能有两种情况:
(1)若pk=pj,则表明在模式串中
‘p1...pk' = 'pj-k+1...pj'
并且不可能存在k'>k满足登时,这就是说next[j+1]=k+1,即
next[j+1]=next[j]+1
(2) 若pk!=pj,则表明在模式串中
‘p1...pk' != 'pj-k+1...pj'
下面部分是关键!
此时可把求next函数值的问题看成是一个模式匹配的问题,整个模式串既是主串又是模式串,而在当前的匹配中已有
(放在下一篇中)
你问我生命中还有什么可追寻?