KMP算法—终于全部弄懂了 k. |0 ]' E. N( Q简介& y& D/ _& r: Z0 X6 c9 \
KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。! w- m h9 Z- b! p6 I, v
4 m5 I5 R+ e8 t* \* G
5 R8 K0 s. S; p0 a c( S$ A. I提取加速匹配的信息* |! i, `1 h0 D) p) r
上面说道 KMP 算法主要是通过消除主串指针的回溯来提高匹配的效率的,那么,它是则呢样来消除回溯的呢?就是因为它提取并运用了加速匹配的信息! m: M, A; O, n; D+ p7 K& J; O 这种信息就是对于每模式串 t 的每个元素 t j,都存在一个实数 k ,使得模式串 t 开头的 k 个字符(t 0 t 1…t k-1)依次与 t j 前面的 k(t j-k t j-k+1…t j-1,这里第一个字符 t j-k 最多从 t 1 开始,所以 k < j)个字符相同。如果这样的 k 有多个,则取最大的一个。模式串 t 中每个位置 j 的字符都有这种信息,采用 next 数组表示,即 next[ j ]=MAX{ k }。 6 P0 B6 c+ k" c6 [, V& ?; O1 v 6 T: F1 l L: N- M M4 j 加速信息,即数组 next 的提取是整个 KMP 算法中最核心的部分,弄懂了 next 的求解方法,也就弄懂了 KMP 算法的十之七八了,但是不巧的是这部分代码恰恰是最不容易弄懂的…… # A- n' T- _! s) O; s# r/ L * U) j" W' E+ s; t先上代码 ) i/ V+ I( `/ k0 S- L f) R, Z1 f% s7 V/ D) h% p6 Q# Y$ c1 P1 w0 b9 h4 D
2 H* q/ f! b) t6 H- A2 Fvoid Getnext(int next[],String t) " s- m9 @8 K, U" O* U+ K- X! B{4 y, p" v- B) w4 f2 P: Q- J
int j=0,k=-1; 5 Y3 V0 A+ S$ i$ a& F next[0]=-1;1 V5 P* a6 n+ ]2 `4 D% z& U5 i1 ~
while(j<t.length-1) 5 p$ C: o0 J# Q `% _# x" v, c) Y {% C2 _ t* ]3 C5 m! V
if(k == -1 || t[j] == t[k])$ M" ~6 p! a {
{ : @; B, t+ r! u j++;k++;+ S" K7 O# s% D. Q& b7 ]+ N
next[j] = k; & J9 |8 n+ i6 E) T }( k/ h; a' L0 z4 @8 U1 W
else k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神!) f$ e6 e: S4 R
}9 Y: D- T6 t5 P. Y4 U
} % Q& s3 T' M2 w( m6 [ 5 H+ p2 J3 a/ i7 J2 Vok,下面咱们分三种情况来讲 next 的求解过程' G6 M8 q! @- H8 r
3 V4 @& d; d; o* h5 C & s j# D9 v# m0 K特殊情况 + L7 d I& w0 V( l! _当 j 的值为 0 或 1 的时候,它们的 k 值都为 0,即 next[0] = 0、next[1] =0。但是为了后面 k 值计算的方便,我们将 next[0] 的值设置成 -1。 $ {/ H- k( b# S7 A& [6 I, O' v# ] X7 x! _5 v5 M
+ z) ?5 A- I( f0 |1 T1 F
当 t[j] == t[k] 的情况 . f+ F9 T2 {/ E" y3 k( j举个栗子* }, j8 F" g; A1 w& ^