KMP前缀表

时间:2012-12-09 21:36:30

标签: string algorithm data-structures pattern-matching

我正在阅读有关字符串匹配的KMP 它需要通过构建前缀表来预处理模式 例如,对于字符串ababaca,前缀表为:P = [0, 0, 1, 2, 3, 0, 1]
但我不清楚数字显示的是什么。我读到,当它移动时找到模式的匹配有帮助,但是我无法将这个信息与表格中的数字联系起来。

8 个答案:

答案 0 :(得分:66)

每个数字都属于相应的前缀(“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;
}

答案 1 :(得分:3)

此代码可能不是最短但易于理解的代码流。 用于计算前缀数组的简单Java代码 -

    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

答案 2 :(得分:2)

Python实现

p='ababaca'

l1 = len(p)

j = 0
i = 1
prefix = [0]

while len(prefix) < l1:
    if p[j] == p[i]:
        prefix.append(j+1)
        i += 1
        j += 1
    else:
        if j == 0:
            prefix.append(0)
            i += 1
        if j != 0:
            j = prefix[j-1]

print prefix

答案 3 :(得分:1)

这是基于接受的答案的无偏移版本,用 C 编写:

void build_confix(char *pattern) {
    int len_pat = strlen(pattern);
    int j, i;
    confix[j = 1] = i = 0; // len pat = 0, no confix.
    for (; j < len_pat; ++j) {
        while (i && pattern[j] != pattern[i])
            i = confix[i];
        if (pattern[j] == pattern[i])
            ++i;
        confix[j+1] = i;
    }
}

用法:

int kmp_find_first(char *test, char *pattern) {
    int len_test = strlen(test);
    int len_pat = strlen(pattern);
    int j = 0, i = 0;                  // solved: done 0 -> match 0.
    for (;j < len_test; ++j) {
        while (i && test[j] != pattern[i])
            i = confix[i];
        if (test[j] == pattern[i])
            ++i;
        if (i == len_pat)
            return j+1-len_pat;
    }
    return -1;
}

答案 4 :(得分:0)

string text =“ ababbabbababbababbabbabb”;     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 []

答案 5 :(得分:0)

我已经尝试过使用Javascript,Open寻求建议。

    s1.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
                // your code here
if(position==0)
{
qImageView.setImageResource(R.drawable.whatever);}
else if(position ==1)
{
qImageView.setImageResource(R.drawable.whatever);}
}

            }

            @Override
            public void onNothingSelected(AdapterView<?> parentView) {
                // your code here
            }

        });

答案 6 :(得分:0)

    String string = "abababca";
    int[]array = new int[string.length()];

    int i = 1;
    int j = 0;

    while(i<string.length()) {
        // if the character are matching the increment the j and i 
        if(string.charAt(j)==string.charAt(i)) {
            array[i] = array[i-1]+1;
            i++;
            j++;
        }else {

            // if not then move j to array[j-1] position and increment i 
            if(j!=0) {
                j = array[j-1];
            }
            i++;
        }   
    }

    for(int k :array) {
        System.out.print(k+" ");
    }

答案 7 :(得分:0)

字符串模式=“ 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) {
    cout<< prefixArray[k]<< endl;
}