データ構造と kmp マッチング アルゴリズムの研究について長い間悩んでいたので、ここに要約します (あくまで私自身のレビューと参考用です)。さて、くだらない話はやめて、直接始めましょう。
目次
データプレフィックステーブルnext[j]とnextval[j]の書き方
次に、2 つのコードを取り出してみましょう。1 つ目は暴力的なマッチング コード、2 つ目は kmp マッチング アルゴリズムです。
ブルート フォース マッチングのアルゴリズム コードは次のとおりです。
まず最初に、もう一度行く前にマッチングするための暴力的なマッチングの解決策について話したいと思います。
暴力的マッチングの原理の説明:
現在のメイン文字列は「abcabaababab」です。
パターン文字列は「abab」です。
今すぐ総当たりマッチを実行してマッチングを開始しましょう。
3 番目を照合したときに、間違っている場合は、「pat」の最初の桁 a と「txt」の 2 桁目を照合します。
最初のものが一致しないことがわかり、引き続き一致します
それでも最初のものは正常に一致しませんでした。その後、一致を続けます
4 桁目がまだ一致しないことが判明したので、1 つずつ下方に一致させ続けますが、最後の一致が成功するまで、ここでは詳細は説明しません。最後に一致しない場合は、- が返されます。 1となり、一致する結果は得られない。
kmp アルゴリズム:
単一一致検索モード (文字列一致アルゴリズム)は非常に効率的で複雑ですが、原理を理解すれば実際には非常に簡単です。次に、次の配列から始めましょう。
kmp に関しては、kmp マッチング アルゴリズムが何であるかを理解するために、プレフィックス マッチング テーブルを知っておく必要があります。kmp の次の配列はプレフィックス テーブルです。
では、先ほど述べたプレフィックス テーブルは何に役立つのでしょうか?
プレフィックス テーブルはフォールバックに使用され、パターン文字列がメイン文字列 (テキスト文字列) と一致しない場合に、パターン文字列がどこから再度一致するかを記録します。
または、上記の例を見てみましょう
主串:“abcabaababab”
パターン文字列は「abab」です。
パターン文字列のnext[j]とnextval[j]を以下のように書きましょう
それでは、彼がどのように一致するかについて話しましょう(それから、この表がどのように書かれているかについて話しましょう)
最初の試合: 3 位に問題があるため、2 番目の試合を行う
2 番目の一致では、テーブルを検索します。j=3、nextval が 0 の場合、0 は空に相当し、1 つ進みます。
3 番目の一致では、j=1 の場合、まだ一致がありませんが、それでも 1 つ前に進みます。
4 番目の一致: 今度は j=4 の場合は一致しません。テーブルを見てみましょう。j=4 の場合は nextval[4]=1 です。最初のビット (a) を次の位置に移動します。 i=7 。
5試合目:
一致が成功したことがわかり、出力が
第6試合:
マッチ成功後もマッチダウンを続ける
第7試合:
テーブルを調べた後も 1 ビット下に移動し、一致は成功します。
上記のプロセスはマッチングのプロセスです(これは私の理解と学習です、違いがある場合はアドバイスをお願いします)
データプレフィックステーブルnext[j]とnextval[j]の書き方
nextval[j] は next[j] に基づいているため、まず next[j] について説明します。次のフォームを書いてみましょう
まず、文字列「abab」に 1 ~ 4 の番号を付けます。次に、一般に (Yan Weimin のデータ構造を学習しています)、以下の図に示すように、最初の 2 つを 0 と 1 としてマークします。
次に、ここで 3 番目の数字 a を確認します。それを確認するかどうかは、最初の 2 桁の接頭辞と接尾辞によって決まります。
プレフィックス: a
サフィックス: b
プレフィックスとサフィックスの最大一致項目を見つけます。ここには何もないので 0 です。j=3 の a の次は 0+1 = 1 です。
ネットワークのプレフィックスとサフィックスを書き出します
接頭辞: a、 ab
接尾辞: a、 ba
ここでは、a と a の間に最大の一致があることがわかり、b の次の値は 1 + 1=2 になります。
私たちはその次の形式を書きました
次にnextval形式を書いてみましょう(次の表に従って書きます)
次の図に示すように、最初の 2 つのデータは 0 と 1 のままです。
3 番目を見てみましょう。3番目の a は 1 より小さいです。j=1 に対応する要素に行きましょう。それが a の場合、a の下の nextval の値を j=3 の a の下に移動します。が a ではない場合、a の下の next の値を nextval に移動します。
4番目を見てみましょう. 同様に、一貫性がある場合はnextvalを2の下に移動し、そうでない場合はbの下の2をnextvalに移動します
次に、2 つのコードを取り出してみましょう。1 つ目は暴力的なマッチング コード、2 つ目は kmp マッチング アルゴリズムです。
ブルート フォース マッチングのアルゴリズム コードは次のとおりです。
# Brute Force Algorithm
def brute_force_algorithm(string, pattern):
n = len(string)
m = len(pattern)
for i in range(n-m+1):
j = 0
while j < m:
if string[i+j] != pattern[j]:
break
j += 1
if j == m:
print("Pattern found at index " + str(i))
# Driver code to test above
string = "abcabaababab"
pattern = "abab"
brute_force_algorithm(string, pattern)
結果は 2 つの値になります
ブルート フォース アルゴリズムの時間計算量
時間の複雑さについて話しましょう
最も複雑な時間は、それぞれを一致させること、つまりそれぞれを一致させることです。
したがって、その時間計算量が O(nxn) であることは難しくありません。
KMP アルゴリズムのコード例
kmp アルゴリズムを見てみましょう。コードは次のとおりです。
# KMP Algorithm
def kmp_algorithm(string, pattern):
n = len(string)
m = len(pattern)
lps = [0] * m
j = 0
compute_lps_array(pattern, m, lps)
i = 0
while i < n:
if pattern[j] == string[i]:
i += 1
j += 1
if j == m:
print("Found pattern at index " + str(i-j))
j = lps[j-1]
elif i < n and pattern[j] != string[i]:
if j != 0:
j = lps[j-1]
else:
i += 1
def compute_lps_array(pattern, m, lps):
len = 0
lps[0] = 0
i = 1
while i < m:
if pattern[i] == pattern[len]:
len += 1
lps[i] = len
i += 1
else:
if len != 0:
len = lps[len-1]
else:
lps[i] = 0
i += 1
# Driver code to test above
string = "abcabaababab"
pattern = "abab"
kmp_algorithm(string, pattern)
演算結果
kmp アルゴリズムの時間計算量
時間計算量: N 個の文字列の開始位置が M 個の文字列で見つかり、長さがそれぞれ m と n であると仮定し、最長の共通プレフィックスおよびサフィックス テーブルの長さを計算するとき、比較回数は [m, 2m]. パターン文字列と部分文字列の比較回数は [n, 2n] 回です。したがって、時間計算量は O(m+n) です。