[KMP] 对最长前后缀匹配表生成步骤的理解

字符串匹配的KMP算法 - 阮一峰的网络日志 (ruanyifeng.com)icon-default.png?t=M276http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html没接触过kmp可以先看看这个👆


例题:

输入样例:

3
aba
5
ababa

输出样例:

0 2

 代码实现:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 1e5+10, M = 1e6+10;

int n, m;
int ne[N];
char s[N], g[M];

int main()
{
    cin >> n >> s + 1 >> m >> g + 1;
    
    //模式串自匹配,初始化偏移数组ne[]
    for(int i = 2, j = 0; i <= n; i ++)
    {
        while(j && s[j+1] != s[i]) j = ne[j];
        if(s[j+1] == s[i]) j ++;
        ne[i] = j;
    }
    
    //两串匹配
    for(int i = 1, j = 0; i <= m; i ++)
    {
        while(j && s[j+1] != g[i]) j = ne[j];
        if(s[j+1] == g[i]) j ++;
        if(j == n)
        {
            cout << i-n << " "; //题意中下标从0开始,因此(i-n+1)-1
            j = ne[j];
        }
    }

    return 0;
}


下面我们输出关键的ne[ ]数组(即最长前后缀匹配表)初始化的步骤

#include <iostream>
#include <cstring>
using namespace std;

const int N = 1e5+10, M = 1e6+10;

int n, m;
int ne[N];
char s[N], g[M];

int main()
{
    cin >> n >> s + 1 >> m >> g + 1;
    
    //模式串自匹配,初始化偏移数组ne[]
    for(int i = 2, j = 0; i <= n; i ++)
    {
        cout << "-----------" << endl;
        while(j && s[j+1] != s[i]){
            printf("s[j(%d)+1] != s[i(%d)] 👉'%c' != '%c'\n", j, i, s[j+1], s[i]);
            j = ne[j];
            printf("j = ne[j] (ne[%d]) = %d\n", j, ne[j]);
        }
        if(s[j+1] == s[i]){
            printf("s[j(%d)+1] == s[i(%d)] 👉'%c' != '%c'\n", j, i, s[j+1], s[i]);
            j ++;
            printf("j++, j = %d\n", j);
        }
        ne[i] = j;
        printf("ne[i(%d)] = j(%d)\n", i, j);
    }
    cout << "-----------" << endl;
    for(int i = 1; i <= n; i ++) cout << ne[i] << " ";
    cout << "#" << endl;
    //两串匹配
    // for(int i = 1, j = 0; i <= m; i ++)
    // {
    //     while(j && s[j+1] != g[i]) j = ne[j];
    //     if(s[j+1] == g[i]) j ++;
    //     if(j == n)
    //     {
    //         cout << i-n << " ";
    //         j = ne[j];
    //     }
    // }

    return 0;
}

测试输入:

10
ababcabcab
14
abababababccba

(注: 字符串下标从1开始)

s[]

a

b

a

b

c

a

b

c

a

b

ne[]

0

0

1

2

0

1

2

0

1

2

下标

1

2

3

4

5

6

7

8

9

10

对比参照输出: 

(括号内表示的是i / j此时的值)

-----------
ne[i(2)] = j(0)
-----------
s[j(0)+1] == s[i(3)] 👉'a' == 'a'
j++, j = 1
ne[i(3)] = j(1)
-----------
s[j(1)+1] == s[i(4)] 👉'b' == 'b'
j++, j = 2
ne[i(4)] = j(2)
-----------
s[j(2)+1] != s[i(5)] 👉'a' != 'c'
j = ne[j(0)] = 0
ne[i(5)] = j(0)
-----------
s[j(0)+1] == s[i(6)] 👉'a' == 'a'
j++, j = 1
ne[i(6)] = j(1)
-----------
s[j(1)+1] == s[i(7)] 👉'b' == 'b'
j++, j = 2
ne[i(7)] = j(2)
-----------
s[j(2)+1] != s[i(8)] 👉'a' != 'c'
j = ne[j(0)] = 0
ne[i(8)] = j(0)
-----------
s[j(0)+1] == s[i(9)] 👉'a' == 'a'
j++, j = 1
ne[i(9)] = j(1)
-----------
s[j(1)+1] == s[i(10)] 👉'b' == 'b'
j++, j = 2
ne[i(10)] = j(2)
-----------
0 0 1 2 0 1 2 0 1 2 #
posted @ 2022-04-02 15:45  泥烟  阅读(28)  评论(0编辑  收藏  举报