額, 因為在準備考研,基本上不部落格了,重新遇到了kmp演算法,心血來潮,所以就來搗鼓一下了,沒錯,我來裝 x 的 ,我的麒麟臂在早已飢渴難耐了。
想必來看kmp演算法的人,都知道kmp演算法是拿來幹嘛的,實現字串模式匹配的高效演算法,不過拿去其他模式匹配應該也可以,只要你想得到。現在再重述一遍演算法思想:
假設已有: 目標串 t[0…n-1],模式串 p[0…m-1] ,注:(t[i…j] 理解成tit
i+1.
..tj
t_t_...t_
titi+
1..
.tj
, $ 0 \lt i \lt n-1$),p也如此理解。
不失一般性,從 t 中的第 s ( 0≤s
≤n−1
0 \le s \le n-1
0≤s≤n−
1 ) 個位置與 p 中 第 j ( $ 1 \le j \le m-1$ ) 個位置匹配失敗。 則此時有 t[s…s+j-1] = p[0…j-1],按照樸素演算法,下一步是將從 ts+
1t_
ts+1
開始與 p 比較,若匹配成功將有 t[s+1…s+m] = p[0…m-1],也即有 t[s+1…s+j-1] = p[0…j-2]。
綜合,已有條件:
t[s…s+j-1] = p[0…j-1] →ts
ts+1
..ts
+j−1
=p0p
1..p
j−
1\to t_t_..t_ = p_p_..p_
→tsts
+1.
.ts+
j−1
=p0
p1.
.pj−
1t[s+1…s+j-1] = p[0…j-2] →ts
+1ts
+2..
ts+j
−1=p
0p1.
.pj−
2\to t_t_..t_ = p_p_..p_
→ts+1
ts+2
..t
s+j−
1=p
0p1
..p
j−2
聯合1、2可得, p0p
1..p
j−2=
p1..
pj−1
p_p_..p_ = p_..p_
p0p1
..pj
−2=
p1.
.pj−
1,即p[0…j-2] = p[1…j-1]
上面的推導表明,只有當 p[0…j-2] = p[1…j-1] 成立時,才會有 t[s+1…s+m] = p[0…m-1]。 如果 p[0…j-2] $ \ne$ p[1…j-1] ,必然導致 t[s+1…s+m] $ \ne$ p[0…m-1]。
所以自然就不用進行t從s+1開始的模式匹配,而是嘗試從s+2開始,如果等式不成立, 就繼續嘗試s+3開始, 直到第k 次, 首次使得:
∗ ∗認
住這傢伙
∗∗p[
0..k]=
p[j−
k+
1..j−1
]**認住這傢伙**p[0..k] = p[j-k+1..j-1]
∗∗認住這家
夥∗∗p
[0..
k]=p
[j−k
+1..
j−1]
成立。這個時候觀察 p[j-k+1…j-1] 有:
t[s+j-k+1…s+j-1] = p[j-k+1…j-1] = p[0…k] →
\to→ t[s+j-k+1…s+j-1] = p[0…k] — 公式 3
因為之前是在第 j 個匹配失敗的,然後又確認了上的 3 式的成立,所以我們很很愉快的從 pk+
1p_
pk+1
與 ss+
js_
ss+j
開始比較了。後面的比較也是不斷的重複上述的步驟。可以發現比較過的t是不再回溯的,所以效率很高。下面將以next(j) 表示第j個匹配失敗後,返回的k值,即下一次要與 t[s+j] 比較的 p[k], 這裡明確一點, 返回的k值, 必需滿足 p[0…k] = p[j-k+1…j-1] 。
接著,我們將問題轉換到了找 k 值,假設已經知道 next(j) = k,現在要求 next(j+1) 。
對於next(j) = k ,明確知道 k 代表的是p[ j ] 與t[s+j]匹配失敗後,下乙個要與 t[s+j] 匹配的位置, 至於p[ k ] 與 t[ s+j ] 是否相等,是不知道的,根據 k 值,我們有:
p[j-k…j-1] = p[0…k-1] = t[s+j-k…s+j-1]
現在,假設在第 j+1 次匹配失敗, 則有 p[0…j] = t[s…s+j] →
\to→ p[j-k…j] = t[s-k…s+j] 。
此時分兩種情況:
(1) p[k] = p[j]
觀察 p[0…k-1] 和 p[j-k…j] ,已有 p[j-k…j-1] = p[0…k-1] ,若 p[k] = p[j] 則有 p[0…k] = p[j-k…j] ,即我們找到了第 j+1 次匹配失敗時,應該返回下乙個與 t[s+j+1] 比較的位置, next(j+1) = k+1 。
(2) p[k] != p[j]
但是我們有 p[j-k…j-1] = p[0…k-1] , 問題模擬成 p[k] 與 p[j] 匹配失敗, 則需要在找到乙個 h = next(k) ,使得 p[0…h-1] = p[k-h…k-1] ,再比較 p[h] 與 p[j] ,若相等,返回 h+1,此時有p[h+1] 與 t[s+j+1] 進行匹配。若p[h] != p[j] ,繼續重複步驟(2),直至傳入 next() 的引數為0時,返回 -1 表示失敗,即p[0…j-1] 中沒有乙個等於 p[j] 的,此時 s := s+1 ,目標串向前推進一步。
下面將根據上述分析過程,寫出遞迴演算法計算第j個位置匹配失敗後應該返回的k值。
演算法將以兩種形式給出,第一種是偽**,第二種是c++**。
偽**:
c++**:next(p, j)
if j == 0
return -1
k = next(p, j-1)
while k != -1
if p[k] = p[j-1]
return k+1
k = next(p, k)
return k+1
//教材**
next(int next)
else k = next[k]; //p[j-1] != p[k] , 往p[0..k-1] 中找到與 p[j-1]相等的位置 }}
int next(string p, int j)
while( k != -1 );
return k + 1;
}//配上乙個kmp, 返回的是1..n形式位置。嗯...沒有在怎麼測試過。
int kmp(string t, string p)
{ int s, j ;
s = j = 0;
while( abs(j) < p.length() && s < t.length() )
{cout《遞迴演算法雖然效率低,每次都要重新計算乙個 next 值,但是更加的直觀,讓我們了解kmp是如何實現的,有時間+有興趣就將遞迴改寫成非遞迴,並用陣列將結果存起來,當然你可以用乙個小技巧,呼叫next()一次,結果存一起,也是可以的拉。一開始,還以為能夠很好的 control 住。最後…希望能有點幫助把…還有參考了 殷人昆主編的《資料結構c++版》。
KMP演算法及python實現
kmp演算法是一種在字串匹配中應用十分廣泛 也十分高效的演算法,就是查詢模式串 子串 在目標串 主串 現的位置,具體的問題可參考leetcode 28.實現strstr 題面如下圖所示。最暴力的演算法就是 模式串的第0位與目標串的第0位進行比較,如果匹配,則比較模式串的第1位與目標串的第1位 如果不...
KMP演算法及python實現
knuth morris pratt kmp 演算法是解決字串匹配問題的經典演算法,下面通過乙個例子來演示一下 給定字串 bbc abcdab abcdabcdabde 檢查裡面是否包含另乙個字串 abcdabd 從頭開始依次匹配字元,如果不匹配就跳到下乙個字元 直到發現匹配字元,然後經過乙個內迴圈...
KMP演算法分析
根據博主july的所載,記錄個人理解心得 紅色部分為個人理解 1.kmp演算法流程 假設現在文字串s匹配到 i 位置,模式串p匹配到 j 位置 1.如果j 1,或者當前字元匹配成功 即s i p j 都令i j 繼續匹配下乙個字元 當s i p j 時,說明模式串j前面的字元都與文字串i前面對應的字...