KMP算法是一個高效的串匹配算法,常被人戲稱爲‘看毛片算法’,其解決的問題爲:
給定兩個字符串:
t = 'adjfdajfidjfiasidjfosdsfossssfdsd'
p = 'jfidjf'
判定t中是否包含p
首先,我們來看一個樸素的串匹配算法
#coding:utf-8
'''
樸素的串匹配法
'''
def naive_matching(t,p):
m, n = len(p), len(t)
i, j = 0, 0
while i < m and j < n:
if p[i] == t[j]:
i, j = i + 1, j + 1
else: #字符不同,則考慮下一個位置
i, j = 0, j-i+1
if i == m: #i==m表示找到匹配,則返回下標。
return j-i
return -1 #無匹配時,返回特殊值
KMP算法
#coding:utf-8
'''
KMP看毛片算法:
1、樸素的匹配算法,其時間複雜度爲O(n*m),KMP的時間複雜度爲O(n+m)
2、其基本思想爲匹配中不回溯,關鍵點在於匹配失敗時模式串如何前移。
3、核心點在於定義一個長度爲m的轉移函數pnext,其含義爲一個固定的字符串的最長前綴和最長後綴。
4、關於最長前綴和最長後綴:
比如:abcsksabc,那麼這個數組的最長前綴和最長後綴相同必然是abc。
cbcbc,最長前綴和最長後綴相同是cbc。
abcbc,最長前綴和最長後綴相同是不存在的。
**注意最長前綴:是說以第一個字符開始,但是不包含最後一個字符。
比如aaaa相同的最長前綴和最長後綴是aaa。**
對於目標字符串ptr,ababaca,長度是7,所以
pnext[0],pnext[1],pnext[2],pnext[3],pnext[4],pnext[5],pnext[6]分別計算的是
a,ab,aba,abab,ababa,ababac,ababaca的相同的最長前綴和最長後綴的長度。
由於a,ab,aba,abab,ababa,ababac,ababaca的相同的最長前綴和最長後綴是
“”,“”,“a”,“ab”,“aba”,“”,“a”,所以next數組的值是[-1,-1,0,1,2,-1,0],
這裏-1表示不存在,0表示存在長度爲1,2表示存在長度爲3。這是爲了和代碼相對應。
比如pnext中某個字符對應的值是4,則在該字符後的下一個字符不匹配時,可以直接移動往前移動ptr 5個長度,再次進行比較判別
'''
#開始構造pnext表函數
def gen_pnext(p):
i, k, m = 0, -1, len(p)
pnext = [-1]*m #初始數組全爲-1
while i< m-1: #生成下一個pnext元素
if k== -1 or p[i] == p[k]:
i, k = i+1, k+1
if p[i] == p[k]:
pnext[i] = pnext[k]
else:
pnext[i] = k
else:
k = pnext[k]
return pnext
def matching_KMP(t, p, pnext):
'''
毛片算法主程序
'''
j, i = 0, 0
n, m = len(t), len(p)
while j < n and i < m:
if 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 #無匹配則返回特殊值