web-dev-qa-db-ja.com

KMPプレフィックステーブル

文字列のマッチングについてKMPについて読んでいます。
プレフィックステーブルを作成して、パターンの前処理が必要です。
たとえば、文字列ababacaの場合、プレフィックステーブルは次のとおりです。P = [0, 0, 1, 2, 3, 0, 1]
しかし、数字が何を示しているのか明確ではありません。私はそれがシフトするときにパターンの一致を見つけるのに役立つと読みましたが、この情報を表の数字と結び付けることはできません。

33
Cratylus

すべての番号は、対応するプレフィックス(「a」、「ab」、「aba」、...)に属し、プレフィックスごとに、プレフィックスに一致するこの文字列の最長のサフィックスの長さを表します。ここでは、文字列全体を接尾辞または接頭辞としてカウントしません。これは自己接尾辞および自己接頭辞と呼ばれます(少なくともロシア語では、英語の用語についてはわかりません)。

したがって、文字列「ababaca」があります。それを見てみましょう。 KMPは、空でないプレフィックスごとにプレフィックス関数を計算します。 s[i]を文字列として、p[i]を接頭辞関数として定義しましょう。プレフィックスとサフィックスは重複する場合があります。

+---+----------+-------+------------------------+
| i |  s[0:i]  | p[i]  | Matching Prefix/Suffix |
+---+----------+-------+------------------------+
| 0 | a        |     0 |                        |
| 1 | ab       |     0 |                        |
| 2 | aba      |     1 | a                      |
| 3 | abab     |     2 | ab                     |
| 4 | ababa    |     3 | aba                    |
| 5 | ababac   |     0 |                        |
| 6 | ababaca  |     1 | a                      |
|   |          |       |                        |
+---+----------+-------+------------------------+

文字列Sのプレフィックス関数を計算する単純なC++コード:

vector<int> prefixFunction(string s) {
    vector<int> p(s.size());
    int j = 0;
    for (int i = 1; i < (int)s.size(); i++) {
        while (j > 0 && s[j] != s[i])
            j = p[j-1];

        if (s[j] == s[i])
            j++;
        p[i] = j;
    }   
    return p;
}
74
imslavko

このコードは最短ではないかもしれませんが、コードの流れを理解するのは簡単です。単純なJava prefix-Array-を計算するためのコード

    String pattern = "ababaca";
    int i = 1, j = 0;
    int[] prefixArray = new int[pattern.length];
    while (i < pattern.length) {

        while (pattern.charAt(i) != pattern.charAt(j) && j > 0) {
            j = prefixArray[j - 1];

        }
        if (pattern.charAt(i) == pattern.charAt(j)) {
            prefixArray[i] = j + 1;
            i++;
            j++;

        } else {
            prefixArray[i] = j;
            i++;
        }
    }

    for (int k = 0; k < prefixArray.length; ++k) {
        System.out.println(prefixArray[k]);
    }

必要な出力を生成します-

0 0 1 2 3 0 1

3

string text = "ababbabbababbababbabb"; static int arr [30];

int i = 1;
while (i < text.length())
{
    int j = 0;
    int value = 0;
    while (((i + j) < text.length()) && (text[j] == text[i + j]))
        val[i + j] = ++value, j++;
    i += j + 1;
}

val []に保存された必要な出力

0
MOHAMED SABTHAR