詳解KMP演算法以及python如何實現
演算法思路
Knuth-Morris-Pratt(KMP)演算法是解決字串匹配問題的經典演算法,下面通過一個例子來演示一下:
給定字串"BBC ABCDAB ABCDABCDABDE",檢查裡面是否包含另一個字串"ABCDABD"。
1.從頭開始依次匹配字元,如果不匹配就跳到下一個字元
2.直到發現匹配字元,然後經過一個內迴圈嚴查字串是否匹配
3.發現最後一個D不匹配,下面就該思考應該把字串向右移動多少個位置呢?傳統做法可能是移動一格,KMP演算法就創新在這裡。KMP演算法通過查詢一個Partial Match Table(表記憶體有字串資訊),然後計算出需要移動的步數,這個表後面會介紹怎麼來的。
這裡我們看到D前面是B,查表得到第二個B對應的是2,所以 移動數 = 已匹配字元數 - 查表所得數 也就是 6 - 2 = 4, 需要向右移動四格。
下面也是重複這個步驟
直到發現匹配或者字元長度超出(未發現匹配)。
Partial Match Table
那麼這個查詢的表是怎麼來的呢?仍然以"ABCDABD"為例
- "A"的字首和字尾都為空集,共有元素的長度為0;
- "AB"的字首為[A],字尾為[B],共有元素的長度為0;
- "ABC"的字首為[A,AB],字尾為[BC,C],共有元素的長度0;
- "ABCD"的字首為[A,AB,ABC],字尾為[BCD,CD,D],共有元素的長度為0;
- "ABCDA"的字首為[A,ABC,ABCD],字尾為[BCDA,CDA,DA,A],共有元素為"A",長度為1;
- "ABCDAB"的字首為[A,ABCD,ABCDA],字尾為[BCDAB,CDAB,DAB,B],共有元素為"AB",長度為2;
- "ABCDABD"的字首為[A,ABCDA,ABCDAB],字尾為[BCDABD,CDABD,DABD,ABD,BD,D],共有元素的長度為0。
python實現
def partial_table(p): '''''partial_table("ABCDABD") -> [0,1,2,0]''' prefix = set() res = [0] for i in range(1,len(p)): prefix.add(p[:i]) postfix = {p[j:i + 1] for j in range(1,i + 1)} #print(p[:i+1],prefix,postfix,prefix & postfix or {''}) res.append(len((prefix & postfix or {''}).pop())) return res def kmp_match(s,p): m = len(s); n = len(p) cur = 0 # 起始指標cur table = partial_table(p) while cur <= m - n: #只去匹配前m-n個 for i in range(n): if s[i + cur] != p[i]: cur += max(i - table[i - 1],1) # 有了部分匹配表,我們不只是單純的1位1位往右移,可以一次移動多位 break else: return True # loop從 break 中退出時,else 部分不執行。 return False print partial_table1("ABCDABD") print kmp_match("BBC ABCDAB ABCDABCDABDE","ABCDABD")
以上就是詳解KMP演算法以及python如何實現的詳細內容,更多關於python實現KMP演算法的資料請關注我們其它相關文章!