KMP算法—终于全部弄懂了% S0 U& ^4 s' s
简介 # {8 |* r$ h: N% \ Q& v KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。1 u) m% o0 p- ]1 j( n9 h, A( e
. H6 V# f! Z2 e J9 G1 f. s( e) q8 B
提取加速匹配的信息7 f9 j. I' U4 t7 ]; y9 Q3 ~5 {
上面说道 KMP 算法主要是通过消除主串指针的回溯来提高匹配的效率的,那么,它是则呢样来消除回溯的呢?就是因为它提取并运用了加速匹配的信息!8 l: l2 z1 z: {$ {) l" _
这种信息就是对于每模式串 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 }。; H8 ?7 b T; ^9 [
9 c b5 G# }2 y4 I* `
加速信息,即数组 next 的提取是整个 KMP 算法中最核心的部分,弄懂了 next 的求解方法,也就弄懂了 KMP 算法的十之七八了,但是不巧的是这部分代码恰恰是最不容易弄懂的…… h, H! E$ d% ?2 e& [0 a5 ~
: H, v0 E. e2 h3 Y. v
先上代码 / B2 _- R& j& M$ X' U! n" K' L9 g1 v5 u, s. `2 u9 D
2 D$ P& P2 e' N; W6 \void Getnext(int next[],String t) : p2 s: z1 @& Q{& H- J" T/ z- d5 i
int j=0,k=-1; + A8 |, ?, A- i8 v5 G next[0]=-1;# p* Q9 V" ^5 R0 Y* d! i7 l
while(j<t.length-1) Y; o& X9 h* H0 Q; [& a+ E { 3 \& ~4 t# Z+ t& o, e% F) M if(k == -1 || t[j] == t[k]) 1 n5 }# w U5 \5 ` {" s: ]+ k& Q: _! M% m9 e' I# a+ p
j++;k++; 0 F6 v" @1 G' q) _) U) T R n next[j] = k;8 j) O$ {* X/ m0 y1 B! \8 U) y0 s
}9 t; @" }4 a& ~
else k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神!; D# z6 [$ ]* {4 n
} ' s A, ^; R9 }4 Y7 b} , t/ j* ^- b8 j/ I ; m; Y% e3 W- \0 O! h) g& h, nok,下面咱们分三种情况来讲 next 的求解过程 6 `8 b" a5 S" c6 B# \8 ]5 ]6 \- N
4 ?- t( H4 n% I+ l特殊情况6 u" T! x$ O, D# c1 E5 N+ h
当 j 的值为 0 或 1 的时候,它们的 k 值都为 0,即 next[0] = 0、next[1] =0。但是为了后面 k 值计算的方便,我们将 next[0] 的值设置成 -1。' O! W/ ?( f1 ~
: K1 z: E/ O' E( k! s
: o4 i" Y. ^3 C3 B) L/ T" Q
当 t[j] == t[k] 的情况 % V0 f: p% U$ W [' y+ W" y举个栗子9 I5 @: k5 J9 K9 o ~/ o: _% \" }