KMP算法—终于全部弄懂了* \8 o! `1 U% R! \6 p
简介 - G! |( @0 [5 B( H0 h& C. \ KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。# F' ?. y9 a8 r; X: t( V* v1 B
/ D+ C' I' _. p! {! z* Z
, k/ \- v% n X) M" T! l, E提取加速匹配的信息1 n/ _8 D) ~8 B) r
上面说道 KMP 算法主要是通过消除主串指针的回溯来提高匹配的效率的,那么,它是则呢样来消除回溯的呢?就是因为它提取并运用了加速匹配的信息!" \( M+ ^4 ^# |
这种信息就是对于每模式串 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 }。" \* |3 D1 a' A5 Z& z( |5 E, t
; M0 Q6 M1 b5 I1 B" h0 f* F 加速信息,即数组 next 的提取是整个 KMP 算法中最核心的部分,弄懂了 next 的求解方法,也就弄懂了 KMP 算法的十之七八了,但是不巧的是这部分代码恰恰是最不容易弄懂的…… / }* }0 F+ b5 u2 W( ?8 M 1 j$ e: p; \( x- V! @9 i4 v! ~+ I先上代码 9 e, w6 t5 E1 W, z" S - D1 x2 H0 s5 F2 \$ D) } 3 e, |( h8 r+ B: h1 ~void Getnext(int next[],String t)6 T" W6 y* n o/ ]
{ 0 S# a6 e0 ]! p. C& T0 V( n _ int j=0,k=-1;" s0 s5 n2 E" {+ X3 ?& P
next[0]=-1;. h/ r0 Q' o" D
while(j<t.length-1) / X$ q6 B. z( O" R$ N# c/ I$ v {0 X; q' |) v$ `! O& p9 |* ]
if(k == -1 || t[j] == t[k]) ( `6 J* W$ U9 M4 m2 X {' _: o# a( e9 G% Z
j++;k++;1 e2 X7 Q7 B, u! M6 s3 Z
next[j] = k;. J) Z0 K/ J, a% }" i' R
} . @" n. e* v/ n. d else k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神!; H& o8 \5 f7 b& p, F" G: b$ b
} # ~' a b+ S; I, i- \3 U; a$ }} 0 G* R3 b$ d" L. M/ F3 B! } 0 v) Y% [1 |& T: Lok,下面咱们分三种情况来讲 next 的求解过程1 ]: s' ^ s% W7 e9 Q
" B" a. V1 n4 g0 }( \
* { S: q+ R* T2 h6 z
特殊情况 # g# w7 A5 n0 d; _: p5 a. J当 j 的值为 0 或 1 的时候,它们的 k 值都为 0,即 next[0] = 0、next[1] =0。但是为了后面 k 值计算的方便,我们将 next[0] 的值设置成 -1。 3 ^4 n% A* U2 n% h9 j/ M 5 C+ t* @ M" g& M; _! w) ]9 V: }' G! A2 j3 U, j
当 t[j] == t[k] 的情况8 `2 }7 E4 d8 C6 W2 Y" v: U) v
举个栗子 R8 v! V6 |# e, A$ q