KMP

2021-11-30 常用算法 KMP

# 一、算法思想

KMP 算法的核心思想是,每当一趟匹配过程中出现字符不匹配情况时,不需要将模板串 PP 移至开头,而是利用已经得到的「部分匹配」的结果将模板串向右移动尽可能短的距离后,再继续比较。

# 二、算法模板

C++

// s[] 是长文本,长度为 n
// p[] 是模式串,长度为 m

// 求模式串的 next 数组
for (int i = 2, j = 0; i <= m; i++) {
    while (j && p[i] != p[j + 1]) j = ne[j];
    if (p[i] == p[j + 1]) j++;
    ne[i] = j;
}

// 匹配过程
for (int i = 1, j = 0; i <= n; i++) {
    while (j && s[i] != p[j + 1]) j = ne[j];
    if (s[i] == p[j + 1]) j++;
    if (j == m) {
        j = ne[j];
        // 匹配成功后的逻辑
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 三、代码实战

# AcWing 0831


题目:KMP 字符串

给定一个模式串 SS,以及一个模板串 PP,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模板串 PP 在模式串 SS 中多次作为子串出现。

求出模板串 PP 在模式串 SS 中所有出现的位置的起始下标。

输入格式

第一行输入整数 MM,表示字符串 PP 的长度。

第二行输入字符串 PP

第三行输入整数 NN,表示字符串 SS 的长度。

第四行输入字符串 SS

输出格式

共一行,输出所有出现位置的起始下标(下标从 00 开始计数),整数之间用空格隔开。

数据范围

1M1051 \le M \le 10^5
1N1061 \le N \le 10^6

输入样例:

3

aba

5

ababa

输出样例:

0 2

解答代码:

#include <iostream>

using namespace std;

const int N = 1000010, M = 100010;

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

int main()
{
    cin >> m >> p + 1 >> n >> s + 1;

    // 求模式串的 next 数组
    for (int i = 2, j = 0; i <= m; i++) {
        while (j && p[i] != p[j + 1]) j = ne[j];
        if (p[i] == p[j + 1]) j++;
        ne[i] = j;
    }
    
    // 匹配过程
    for (int i = 1, j = 0; i <= n; i++) {
        while (j && s[i] != p[j + 1]) j = ne[j];
        if (s[i] == p[j + 1]) j++;
        if (j == m) {
            j = ne[j];
            printf("%d ", i - m);
        }
    }

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Last Updated: 2023-01-28 4:31:25