今天学习的是KMP算法。
该算法是由三个外国人发明的,他们名字的首字母构成了该算法的名字。
先简单的讲一下这个算法是干什么的。粗暴的说这事一个高效的寻找字符串的算法,它的存在,大大的缩短了查找的时间。其巧妙之处在于……
看得出来,非常的巧妙😉😂。
见上图,在查找中,开头就有ABAB的重复。按照一般暴力的算法,子串的第一个A将会与主串中的第一个B对其,然后继续匹配。但是在KMP算法中,将会这样子:
KMP算法将会标记子串已经匹配过的前缀和后缀,并在下一次的查询中,子串的前缀直接跳转至主串的后缀,并进行匹配。于是就这样,直到完成匹配。
有一道题目非常好
P3375 【模板】KMP
这道题目生动的诠释了什么是kmp
# 【模板】KMP
## 题目描述
给出两个字符串 $s_1$ 和 $s_2$,若 $s_1$ 的区间 $[l, r]$ 子串与 $s_2$ 完全相同,则称 $s_2$ 在 $s_1$ 中出现了,其出现位置为 $l$。
现在请你求出 $s_2$ 在 $s_1$ 中所有出现的位置。
定义一个字符串 $s$ 的 border 为 $s$ 的一个**非 $s$ 本身**的子串 $t$,满足 $t$ 既是 $s$ 的前缀,又是 $s$ 的后缀。
对于 $s_2$,你还需要求出对于其每个前缀 $s'$ 的最长 border $t'$ 的长度。
## 输入格式
第一行为一个字符串,即为 $s_1$。
第二行为一个字符串,即为 $s_2$。
## 输出格式
首先输出若干行,每行一个整数,**按从小到大的顺序**输出 $s_2$ 在 $s_1$ 中出现的位置。
最后一行输出 $|s_2|$ 个整数,第 $i$ 个整数表示 $s_2$ 的长度为 $i$ 的前缀的最长 border 长度。
## 样例 #1
### 样例输入 #1
```
ABABABC
ABA
```
### 样例输出 #1
```
1
3
0 0 1
```
以上是题目原文
#include<iostream>//P3375 【模板】KMP
using namespace std;
int kmp[1000005];
void lessonl()
{
int lena, lenb, pos = 0;
string a, b;
cin >> a >> b;
a = '0' + a;
b = '0' + b;
lena = a.size() - 1;
lenb = b.size() - 1;
for (int i = 2; i <= lenb; i++)
{
while (pos && b[i] != b[pos + 1])
pos = kmp[pos];
if (b[pos + 1] == b[i])
pos++;
kmp[i] = pos;
}
pos = 0;
for (int i = 1; i <= lena; i++)
{
while (pos && a[i] != b[pos + 1])
pos = kmp[pos];
if (b[pos + 1] == a[i])
pos++;
if (pos == lenb)
{
printf("%d\n", i - lenb + 1);
pos = kmp[pos];
}
}
for (int i = 1; i <= lenb; i++)
printf("%d ", kmp[i]);
}
int main()
{
lessonl();
return 0;
}
这是答案代码。
代码还是不能完全理解呢,但是整体的思路还是知道的。
明天还是得做做相关的题目呢。