kmp演算法的核心在於失配回溯表——pnext,相比於通過逐個比較來匹配字串的樸素演算法,kmp通過對模式串的分析,可以做到比較指標在主串上不回溯,一直向前。
1. kmp如何實現不回溯?
對於主串 t0 t1....tj,模式串 p在 pi處與 tj 失配,假設 p0~pi-1 存在最長相等前字尾,可以證明將模式串移動至該字首的後一位,再將其與 tj進行比較,不會漏掉可能的匹配,並且可以大大加速匹配過程。並且這種移動與具體主串無關,僅僅與模式串的失配位置 i 有關,可以通過提前分析模式串,得到失配後的串移動表pnext。
2. 如何得到pnext?
pnext表實質上記錄的是模式串中前 i 個元素形成的子串,其最長相等前字尾的大小。即pnext [ i ] 記錄著p0到pi-1的子串最長相等前字尾的大小。
具體實現方法就是用模式串自身去逐個比對自身,由前字尾的定義可知,頭元素沒有相等前字尾,pnext [1]=0。用第0個元素去比對第1個元素,當p0=p1時,pnext [2]=1,接下來比較p1是否等p2;
否則pnext [2]=0,接下來繼續比較p
0是否等p
2.......
更一般的,當已知模式串中pnext [ i-1]=k-1,即 p0~pk
-2與 pi-k~pi-2求pnext [ i ]。分兩種情況:
1)當pi-1=pk-1時,對於i-1的最長相等前字尾,比i-2要多1,那麼可以得到pnext [ i
]=k,指標後移,開始求pnext [ i+1];
2)當pi-1!=pk-1時,這時我們需要在 p0~pk-1中繼續向前找,在 pi-k~pi-1中繼續向後找,尋找新的最長相等前字尾。假設我們尋找到了該串,即字首為 p0~px
-1,字尾為 pi-x~pi-1,那麼由於pi-1!=pk-1,而pi-1=px
-1。表明px
-1!=pk-1,這說明串p0~px
-2一定是pk-1的最長相等前字尾串,即pnext [ k ]=x-1。因此當pi-1!=pk-1時,可以直接比對pi-1是否等於ppnext[ k ]!!!此時問題變為:已知模式串中pnext [ i-1]=k-1,求pnext [ i ],其中i-1實際為k,k-1實際值為x-1。
若比對成功,則pnext [ i ]=x,指標後移,否則直接比對pi-1是否等於ppnext[ pnext[ k ] ]。問題形成了遞迴。
將這種遞迴求值關係與邊界條件相結合,我們注意到當p1!=p0時,pnext [2]=0= -1+1,可以設pnext [0]=-1,則整個求pnext錶值過程可以用乙個函式統一起來。求值過程從1號位值開始。
defmy_pnext(p):
'''模式串的pnext表生成函式
'''m=len(p)
pnext=[-1]*m
i,k=0,-1
while i:
'''當k=-1時,說明pi != p0 ,沒有最大相等前字尾,此時pnext[i]應為0
同樣可以將i,k都加1,進行賦值'''
if k==-1 or p[i]==p[k]:
i,k=i+1,k+1pnext[i]=k
else
: k=pnext[k]
return pnext
相應的kmp函式為:
defmy_kmp(t,p,pnext):
'''t是主串,p是模式串,pnext是模式串kmp演算法的回溯指標表
'''j,i=0,0
n,m=len(t),len(p)
while jand iif i==-1 or t[j]==p[i]:
j,i=j+1,i+1
else
: i=pnext[i]
if i==m:
return j-i
return -1
我對KMP演算法的理解
我對kmp演算法的理解 在過去的幾天,我讀了好幾篇關於 利用kmp演算法查詢字串的解釋 的文章。出於某些原因,沒有一篇是能令我接受和理解的。每當讀到 字首的字尾的字首.這些字眼時,我都有種拿頭撞牆的衝動。最後,經過30分鐘反覆閱讀clrs的幾段文章,我決定坐下來找一些關於文字串匹配的例子,並把過程寫...
對KMP演算法的理解
kmp演算法是一種高效的模式匹配演算法,複雜度可以達到o m n 而普通模式匹配演算法的複雜度為o m n 普通模式匹配演算法 從主串的第乙個字元 或者給定的第pos個字元 開始和子串的第乙個字元開始比較,若相等,則繼續比較後面的字元。若不相等,則從主串本次開始比較的字元的下乙個字元開始,與子串的第...
對KMP演算法的理解
kmp演算法是一種高效的模式匹配演算法,複雜度可以達到o m n 而普通模式匹配演算法的複雜度為o m n 普通模式匹配演算法 從主串的第乙個字元 或者給定的第pos個字元 開始和子串的第乙個字元開始比較,若相等,則繼續比較後面的字元。若不相等,則從主串本次開始比較的字元的下乙個字元開始,與子串的第...