ナレッジポイントの説明:
最初に接頭辞と接尾辞について話しましょう。
たとえば、次の文字列があります:abab
その場合、下付き文字は3になります(接頭辞と接尾辞は両方とも下付き文字の長さより1短く、下付き文字は3で、長さは4です)
プレフィックスは次のとおりです:a、ab、aba
接尾辞は次のとおりです:b、ba、bab
1.KPMアルゴリズムのnext[]配列を取得するには
原理について簡単に説明します。まず、kを使用してプレフィックスの添え字を格納します。まず、j = 0を初期化します(jはパターン文字列の添え字を表すために使用します。常にパターン文字列の各ビットを前のビットと比較します。 1.等しい場合は、現在の位置が前の位置と同じである位置を記録します。主に同じ位置の次の位置、つまり同じ位置を記録します。比較のために同じ位置から開始するのはバックトラックです。同じ位置にあるので、ここtで[j] == t [k]が確立されると、j + 1が必要になります。次の位置が同じかどうかを比較するために、kも+1)、パターン文字列0から始まり、k = -1、next [0]=-1最初の位置にはデフォルト値-1が割り当てられます。
ここで、文字列は="abab"を使用します
最初のループ:
kが-1に等しいかどうかを判断します。等しい場合は、jとkの両方が+1です。
このとき、j = 1、k = 0、next [1] = 0、つまり、プレフィックスの最大長が長さよりも短くなければならないため、2番目の位置(添え字1)のバックトラッキング位置は0のままです。現在の位置の;
2番目のサイクル:
j = 1、k = 0、next [1] = 0; kは-1に等しくない、t [j] == t [k]、t [1] == t [0]、t[1]と判断する= "b"、t [0] = "a"、等しくない
elseを実行します。
k = next [0] =-1
3番目のサイクル:
k ==-1
jとkは両方とも+1、j = 2、k = 0、next [2]=0です
4番目のサイクル:
kは-1に等しくなく、t [2] == t [0]、t [2] =“ a” = t [0] =“ a”と判断され、確立されます
jとkは両方とも+1、j = 3、k = 1、next [3]=1です
このとき、next = [-1,0,0,1]、next [3] = 1は、next [3]で不一致が発生した場合、つまりパターン文字列の添え字が3の場合、「 b "、前のaba Allがターゲット文字列と一致することを示します。したがって、パターン文字列の一致しない位置の前の文字列abaは、ターゲット文字列の一致しない位置の前の最初の3つの値と等しくなければなりません。はabaなので、現時点では、パターン文字列の1の位置に戻るだけで済みます。つまり、パターン文字列のb、パターン文字列bの前にaがあり、ターゲット文字列の前のaは次のようになります。満足。
5番目のサイクル:
kはまだ-1に等しくありません。つまり、前の位置の後の2つの数値を比較してから、それらを比較します。簡単に言えば、各項目を取り出して最初の項目と比較します。等しいものがある場合は、次のものと2番目のもの。アイテムは等しい。
コードは次のように表示されます。
def GetNext(t, next):
j, k = 0, -1
next[0] = -1
while j < len(t) - 1:
if k == -1 or t[j] == t[k]: # 如果k==-1 或者 开始位置和结尾位置有相同的元素
j, k = j + 1, k + 1 # j和k都加1,当前位匹配,则从下一个位置开始匹配,所以k+1;j再进行取下一位判断是否也是匹配,所以也要+1
next[j] = k # 当前位置要取k项
else:#如果不相等,再把k置-1,下一次循环再进行+1操作,j这个位置再存入0,表示无匹配项
k = next[k]
return next
2.KMP機能
原理はBFアルゴリズムと同じですが、唯一の違いは、パターン文字列がターゲット文字列と一致しない場合、パターン文字列は直接バックトラックされませんが、バックトラックされる位置は次の[]テーブルに従ってクエリされることです。パターン文字列、パターン文字列の指定された位置に直接バックトラックする、KMPアルゴリズムのコアはここにありますが、この方法は通常、プレフィックスとサフィックスに同じ要素がある場合、つまり同じ場合にのみ有効です。部分は同じであり、もう比較されません。比較は同じ要素の次の位置から開始されるため、KMPアルゴリズムの最も複雑な部分は、実際にはnext []テーブルを見つけて、パターン文字列のプレフィックスは同じです。その場合は、同じ位置をマークします。次回、バックトラックで0の位置にバックトラックする必要がない場合は、別の位置から開始できます。
def KMP(s, t):
next = [0] * len(t)
next = GetNext(t, next)
print(next)
i, j = 0, 0
while i < len(s) and j < len(t):
if j == -1 or s[i] == t[j]:
i, j = i + 1, j + 1
else:
j = next[j]
if j >= len(t):
return i - len(t)
else:
return -1
完全なコード:
def GetNext(t, next):
j, k = 0, -1
next[0] = -1
while j < len(t) - 1:
if k == -1 or t[j] == t[k]: # 如果k==-1 或者 开始位置和结尾位置有相同的元素
j, k = j + 1, k + 1 # j和k都加1,当前位匹配,则从下一个位置开始匹配,所以k+1;j再进行取下一位判断是否也是匹配,所以也要+1
next[j] = k # 当前位置要取k项
else:#如果不相等,再把k置-1,下一次循环再进行+1操作,j这个位置再存入0,表示无匹配项
k = next[k]
return next
def KMP(s, t):
next = [0] * len(t)
next = GetNext(t, next)
print(next)
i, j = 0, 0
while i < len(s) and j < len(t):
if j == -1 or s[i] == t[j]:
i, j = i + 1, j + 1
else:
j = next[j]
if j >= len(t):
return i - len(t)
else:
return -1
if __name__ == '__main__':
re = KMP('asdfghjsssaaasdfaaaabababcdabd', "ababaaaababaa")
print(re)
結果: