KMP 入门

George222 Lv3

前传:BF 算法

BF 算法即为暴力解法,一位一位向下匹配。

时间复杂度约为

KMP

KMP 算法的主要思想是利用部分匹配信息,避免重复匹配,提高字符串查找效率。

KMP 算法总时间复杂度是 ,匹配用时

为模式串长度, 为目标串长度。

KMP 算法第一步:构造 数组

思路

存储的是 模式串 的最长相同前后缀的长度。

例子如下:

1
2
字符串:`a b a b a`
kmp数组:0 0 1 2 3

aba,前后的 a 相同,故

ababa,前后的 aba 相同,故

代码理解

1
2
3
4
5
6
7
8
9
10
11
12
kmp[1] = 0;
int len1 = strlen(s1 + 1);
int len2 = strlen(s2 + 1);
int j = 0;
for (int i = 2; i <= len2; i++)
{
while (j && s2[i] != s2[j + 1])
j = kmp[j];
if (s2[j + 1] == s2[i])
j++;
kmp[i] = j;
}
  • 代表当前计算 时,前后缀匹配的长度。
  • 逻辑:
    • ,说明 位置也能匹配前后缀相同, 并记录到
    • ,使用 回退,直到可以匹配或

KMP 算法匹配过程

前面说过了:

KMP 算法的主要思想是利用部分匹配信息,避免重复匹配。

我们求相同前后缀就是为了更好的跳跃。

如图所示,由于前后缀相同,我们可以直接跳跃至后缀部分,省去中间部分一位位匹配。

此部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
j = 0;
for (int i = 1; i <= len1; i++)
{
while (j && s1[i] != s2[j + 1])
j = kmp[j];
if (s2[j + 1] == s1[i])
j++;
if (j == len2)
{
cout << i - len2 + 1 << "\n";
j = kmp[j];
}
}

P3375 AC 代码

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
34
35
36
37
38
39
40
#include <bits/stdc++.h>
using namespace std;

char s1[1000005], s2[1000005];
int kmp[1000005];

int main()
{
cin >> s1 + 1;
cin >> s2 + 1;
kmp[1] = 0;
int len1 = strlen(s1 + 1);
int len2 = strlen(s2 + 1);

int j = 0;
for (int i = 2; i <= len2; i++)
{
while (j && s2[i] != s2[j + 1])
j = kmp[j];
if (s2[j + 1] == s2[i])
j++;
kmp[i] = j;
}
j = 0;
for (int i = 1; i <= len1; i++)
{
while (j && s1[i] != s2[j + 1])
j = kmp[j];
if (s2[j + 1] == s1[i])
j++;
if (j == len2)
{
cout << i - len2 + 1 << "\n";
j = kmp[j];
}
}
for (int i = 1; i <= len2; i++)
cout << kmp[i] << " ";
return 0;
}

后记

感谢能看到这里!

欢迎对本文提各种学术性的建议!

图较丑,比较糊,勿喷,谢谢。

  • 标题: KMP 入门
  • 作者: George222
  • 创建于 : 2025-03-16 22:17:20
  • 更新于 : 2025-03-23 14:31:54
  • 链接: https://george110915.github.io/KMP 入门/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论