導入
KMP アルゴリズムは文字列マッチング アルゴリズムであり、Web ページのテキスト検索、テキスト内のパターンのすべての出現の検索、DNA 配列内の特定の配列の検索など、文字列マッチングは広く使用されています。このアルゴリズムは、Knuth、Morris、Pratt によって設計され、線形時間で文字列を照合できるアルゴリズムです。その他のマッチングアルゴリズムとしては、ブルートフォースアルゴリズム、Rabin-Karpアルゴリズム、有限オートマトンアルゴリズム(正規表現、字句解析など)がありますが、ここでは主にKMPアルゴリズムを紹介します。
複雑さ
メイン文字列の長さを n、パターン文字列の長さを m に設定します
マッチング時間計算量 O(n)
補助関数の計算時間計算量 O(m)
補助関数の空間計算量 O(m)
補助関数はパターン文字列を記録します次の配列 プレフィックスとサフィックスの情報により、文字列照合プロセス中のメイン文字列のバックトラックが回避され、O(n) の照合時間の計算量が達成されます。
アルゴリズムの詳しい説明
1. 次の配列
次の配列は、パターン文字列 P の設定 next*[i] = k です。これは、パターン文字列 P のサブスクリプト 0 からサブスクリプト i までのサブストリング内で、同じプレフィックスとサフィックスを持つ文字 k の最大数を意味します。 k <
次の配列は、全体として next* 配列に対して右に 1 位置シフトされ、最初のビットに -1 が追加されます。これは主に使用の便宜のためです。KMP アルゴリズムは、next* 配列を使用して実行することもできます。
例:
パターン文字列 P | ある | b | ある | b | ある | b | c | b |
---|---|---|---|---|---|---|---|---|
索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
次* | 0 | 0 | 1 | 2 | 3 | 4 | 0 | それ |
次 | -1 | 0 | 0 | 1 | 2 | 3 | 4 | 0 |
next*[0] = 0、サフィックスとサフィックスは空の文字列
next*[1] = 0、サフィックスとサフィックスは異なります
next*[2] = 1、最も長い同一のサフィックスとサフィックス「a」があります
next* [3] = 2。最長の同一プレフィックスとサフィックス「ab」があります
。 next*[4] = 3、最長の同一プレフィックスおよびサフィックス「aba」があります。
next*[5] = 4、最長の同一プレフィックスがあります。およびサフィックス「abab」
next*[6] = 0、プレフィックスとサフィックスの両方が異なります
next* 配列解決プロセス
2. KMPアルゴリズム
マッチング処理
上記のマッチング処理では、主文字列は遡りません マッチングに失敗した場合は、次のデータに合わせてパターン文字列の一致位置を調整します 主文字列が一致しない位置は複数一致する場合があります倍になりますが、全体的な複雑さは同じです。O(n) を超えることはありません。KMP アルゴリズムの時間計算量の償却分析は、アルゴリズムの概要にあります。興味がある場合は、ご覧ください。
実装コード
1. 次の配列コードを解く
void getNext(char * p, int * next) {
next[0] = -1;
int i = 0, j = -1;
while (i < (int)strlen(p)) {
if (j == -1 || p[i] == p[j]) {
++i;
++j;
next[i] = j;
} else {
j = next[j];
}
}
}
2.KMPマッチング
int kmp(char * t, char * p) {
int i = 0;
int j = 0;
while (i < (int)strlen(t) && j < (int)strlen(p)) {
if (j == -1 || t[i] == p[j]) {
i++;
j++;
} else {
j = next[j];
}
}
if (j == strlen(p))
return i - j;
else
return -1;
}