knuth-morris-pratt(kmp)演算法是解決字串匹配問題的經典演算法,下面通過乙個例子來演示一下:
給定字串"bbc abcdab abcdabcdabde",檢查裡面是否包含另乙個字串"abcdabd"。
從頭開始依次匹配字元,如果不匹配就跳到下乙個字元
直到發現匹配字元,然後經過乙個內迴圈嚴查字串是否匹配
發現最後乙個d不匹配,下面就該思考應該把字串向右移動多少個位置呢?傳統做法可能是移動一格,kmp演算法就創新在這裡。kmp演算法通過查詢乙個partial match table(表記憶體有字串資訊),然後計算出需要移動的步數,這個表後面會介紹怎麼來的。
這裡我們看到d前面是b,查表得到第二個b對應的是2,所以 移動數 = 已匹配字元數 - 查表所得數 也就是 6 - 2 = 4, 需要向右移動四格。
下面也是重複這個步驟
直到發現匹配或者字元長度超出(未發現匹配)。
那麼這個查詢的表是怎麼來的呢?仍然以"abcdabd"為例
- "a"的字首和字尾都為空集,共有元素的長度為0;
- "ab"的字首為[a],字尾為[b],共有元素的長度為0;
- "abc"的字首為[a, ab],字尾為[bc, c],共有元素的長度0;
- "abcd"的字首為[a, ab, abc],字尾為[bcd, cd, d],共有元素的長度為0;
- "abcda"的字首為[a, ab, abc, abcd],字尾為[bcda, cda, da, a],共有元素為"a",長度為1;
- "abcdab"的字首為[a, ab, abc, abcd, abcda],字尾為[bcdab, cdab, dab, ab, b],共有元素為"ab",長度為2;
- "abcdabd"的字首為[a, ab, abc, abcd, abcda, abcdab],字尾為[bcdabd, cdabd, dabd, abd, bd, d],共有元素的長度為0。
def partial_table(p):
'''''partial_table("abcdabd") -> [0, 0, 0, 0, 1, 2, 0]'''
prefix = set()
res = [0]
for i in range(1, len(p)):
prefix.add(p[:i])
postfix =
#print(p[:i+1],prefix,postfix,prefix & postfix or )
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實現
kmp演算法是一種在字串匹配中應用十分廣泛 也十分高效的演算法,就是查詢模式串 子串 在目標串 主串 現的位置,具體的問題可參考leetcode 28.實現strstr 題面如下圖所示。最暴力的演算法就是 模式串的第0位與目標串的第0位進行比較,如果匹配,則比較模式串的第1位與目標串的第1位 如果不...
Python程式設計KMP匹配演算法及實現
kmp演算法 字串匹配的一種基本演算法,比如 在bab abcaabcda中匹配字串abcd 即在母串中檢視是否包涵字串 對字串abcd進行檢索 第一步 發現a與b不匹配則,把a向後移動一位 第二步 發現第乙個字元a匹配,再尋找第二個字元b也匹配,再尋找第三個字元c不匹配,按照往常的做法將字串abc...
KMP演算法(Python實現)
關於kmp演算法的原理等請參閱這篇文章 kmp演算法 c 實現 本篇文章只是對kmp用python進行了實現。1.時間複雜度分析 bf演算法的時間複雜度 在最壞的情況下,bf演算法要將目標串的每乙個字元同模式串進行比較一遍,假定目標串長度為m,模式串長度為n,總的時間複雜度為o m n 而對於kmp...