kmp 演算法全稱 knuth-morris-pratt 匹配演算法,常用於字串匹配,時間複雜度 o(n + m),空間複雜度 o(n + m),其中 n 為文字串的長度,m 為模式串的長度。
舉個例子,令文字串 t = 「abaabaaabaaaabaaaaab」 ,模式串 p = 「aabaaaab」 ,當 t 已經匹配到第8位,p 已經匹配到第6位,即 t[3..8] = p[1..6] 時,因為 t[9] ≠ p[7],故匹配失敗。
對於樸素的匹配演算法而言,此時 p 的下標應歸 1,t 的下標應設成 4 重新匹配。但是,在這種情況下,由於 t[3..8] 已知,我們便可以通過找出p[1..6]的乙個字首和 t[3..8] 的乙個字尾使其相等,即找出 p[1..6] 的乙個字首和 p[1..6] 的乙個字尾使其相等,在這個例子中 p[1..6] = 「aabaaa」 ,找出的相等的最長字首和最長字尾(不包括自身)為 「aa」 ,這個過程可以在預處理中進行,故在進行下一輪匹配時t下標不變,p 下標改為 3 繼續匹配,因為 t[7..8] = p[5..6] = p[1..2]。
推廣到一般情況,若 t[i-q..i-1] = p[1..q],此時 t[i] ≠ p[q + 1],則我們可以計算出 p[1..q] 不包括自身的相等最長字首和最長字尾的長度,記為 π[q]。如此一來,因為 t[i-π[q]..i-1] = p[q-π[q]+1..q] = p[1.. π[q]],匹配時可以不更改 t 下標,使 p 下標更改為 π[q],繼續匹配 t[i] 和 p[π[q]]。由於 t 下標不降,故該過程的時間複雜度近似為 o(n)。
現在,我們有乙個問題,那就是如何查詢模式串的乙個字首的相等最長字首和最長字尾的長度(不包括自身),即構建 π 陣列。這個過程可以放在預處理中進行。為了構建 π[i],我們可以用模式串與自身相匹配的方法。仍以前文為例,模式串 p = 「aabaaaab」 ,當 p 分別匹配到第 6 位和第 2 位時,即 p[5..6] = p[1..2],因為 p[7] ≠ p[3],由於 p[6] = p[2] = p[1],所以下一輪匹配時 7 下標不變,3下標改為 π[2]+1(即為2)繼續匹配。
推廣到一般情況,當p分別匹配到i下標和q下標時,即 p[i-q..i-1] = p[1..q],若 p[i] ≠ p[q+1],則因為 p[i-q+π[q]-1..i-1] = p[π[q]..q] = p[1..q-π[q]+1],所以在下一輪匹配中i不變,匹配 p[i] 和 p[π[q]+1]。由於 i 不降,故該過程的時間複雜度近似為 o(m)。
kmp 演算法的偽**如下:
π[1] := q := 0
n := t . length
m := p . length
for i := [2 , m]
while (q > 0 && p[i] ≠ p[q + 1])
q := π[q]
if (p[i] = p[q + 1])
q := q + 1
π[i] := q
q := 0
for i := [1 , n]
while (s > 0 && t[i] ≠ p[q + 1])
q := π[q]
if (t[i] = p[q + 1])
q := q + 1
if (m = q)
print i-m+1
q := π[q]
當 p = 「aabaaaab」 時,π 陣列取值如下:
ip[i]
π[i]1a
02a1
3b04
a15a
26a2
7a28
b3說到這裡,我們不禁想:由於從表面看,這個演算法裡存在二重迴圈,這樣能達到線性時間複雜度嗎?
我們說,其實是可以的。觀察 π 陣列的構造過程,我們可以發現對於一切 i = [1, m],一定有 i > π[i],此時無論執不執行 while 迴圈則必有 π[i] ≤ π[i - 1] + 1,在最壞情況下最多執行 m 次 while 迴圈,而此時必有 i = m 。也就是說,π 陣列的構造最多迴圈 2m 次。同理可得,匹配過程最多迴圈 2n 次。於是 kmp 演算法的時間複雜度可近似為 o(m + n) 。
下面是幾道 kmp 演算法的習題:poj1961,poj2406,poj2752,poj3461。
KMP演算法 字串匹配
kmp演算法基本思想 我們在用常規的思想做 字串匹配時候是 如 對如 字元如果 t abab 用p ba 去匹配,常規思路是 看 t 第乙個元素 a 是否 和p 的乙個 b 匹配 匹配的話 檢視各自的第二個元素,不匹配 則將 t 串的 第二個元素開始 和 p 的第乙個匹配,如此 一步一步 的後移 來...
KMP字串匹配演算法
kmp核心思想 計算模式串的next陣列,主串的索引在比較的過程中不回朔 ifndef kmp h define kmp h class kmp endif include kmp.h include include include using namespace std int kmp calcu...
KMP字串匹配演算法
在介紹kmp演算法之前,先介紹一下bf演算法。一.bf演算法 bf演算法是普通的模式匹配演算法,bf演算法的思想就是將目標串s的第乙個字元與模式串p的第乙個字元進行匹配,若相等,則繼續比較s的第二個字元和p的第二個字元 若不相等,則比較s的第二個字元和p的第乙個字元,依次比較下去,直到得出最後的匹配...