Before Writing
KMP算法主要应用在字符串的匹配上,其中的方法思路是较容易理解的,难点在于如何完成前缀表的构建代码(Next数组)。
本文主要剖析为什么可以通过简单几行代码就可以构建next前缀表,如果想快速了解原理直接跳转至对j = next[j-1]回溯的理解章节。
如果对字符串匹配不了解,可以先看这篇文章,对字符串匹配进行了大致描述,随后可以看代码随想录文章.
看完之后应该对如下概念有一定认知:
Q:字符串的结构和匹配
Q:前缀表
Q:前缀与后缀和最长公共前后缀
Q:BF算法及复杂度
Q:KMP算法思路
Q:next数组的概念
由于KMP算法中next数组的构建代码相对不是容易理解,这里着重介绍一下。
理论基础—next数组
Next和Prefix都可以表示为前缀表的名字,习惯的将其命名为next数组。
在定义next数组的时候,定义下标的方式有两种,如下图所示:
- 左闭右闭
- 即next数组的下标
i代表着主串的前i+1个字符中前后缀重复的字符数 - 此时next数组的第一位被固定为== 0 ==
- 即next数组的下标
- 左闭右开
- 即next数组的下标
i代表着主串的前i个字符中前后缀重复的字符数,当i=0时表示空 - 此时next数组的第一位被固定为== -1 ==
- 即next数组的下标

-
假设模版字符串为‘DABCDABD’,求得左闭右开
next[]数组具体操作过程如下:- 1.首先对‘DABCDABD’标注下标0-7
- 2.从下标0开始依次向后遍历,当
j=0的时候next[j]=-1 - 3.
next[j]的值为下标j的字符前面的子串的最大前后缀匹配字符数- 比如
j=6时,前面子串为‘DABCDA’,‘DA’是最大匹配前缀 - 比如
j=5时,前面子串为‘DABCD’,‘D’是最大匹配前缀

- 比如
-
注:为了方便记忆理解,本文使用左闭右闭的方式用于记录前缀表
next[],其核心就是:- 在
j遇到冲突时,找到冲突的前一位及j-1的next[j-1]作为j的新位置 next[]数组主要是找到每个位置对应的前面子串的最大前后缀匹配数
- 在
next数组代码实现
void getNext(int* next, const string& s) {
int j = -1;
next[0] = j;
for(int i = 1; i < s.size(); i++) { // 注意i从1开始
while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
j = next[j]; // 向前回退
}
if (s[i] == s[j + 1]) { // 找到相同的前后缀
j++;
}
next[i] = j; // 将j(前缀的长度)赋给next[i]
}
}
-
1.首先对next数组进行初始化赋值,将
s模式串传入void getNext(next, S),其中函数中有i,j两个变量- j指向前缀末尾位置,代表着
i之前(包括i)子串的最长相等前后缀的长度,初始化为0 - i指向后缀末尾位置,
i初始化为1,因为后缀不包含第一个字符 for (int i = 1; i < s.size(); i++)
- j指向前缀末尾位置,代表着
-
2.处理前后缀不同的情况
- 前后缀不同证明出现了
s[i]后与s[j]不再匹配了,我们需要找到== 从i-1往前的前缀最大匹配的长度 == - 由于前面我们已经得到了下标小于
i的next数组,为了利用前面的匹配结果,另j-1作为中介,查找next[j-1]即可找到== 从i-1往前的前缀最大匹配的长度 == - 同时,为了在利用
next[j-1]数组时发生越界,规定j>0while (j > 0 && s[j] != s[i]) j = next[j-1];
- 前后缀不同证明出现了
-
3.处理前后缀相同的情况
- 如果
s[i]==s[j],则继续对比下面的字符,并将i处对应的最大匹配长度记录到next数组中j++; s[i] = j; i++;
- 如果
对j = next[j-1]回溯的理解

- 以‘aabaaf’为示例,前后缀相同不同的处理情况和具体步骤:
- 第一步:
j=0, i=1, next初始化为0,此时s[j] == s[i]

- 第二步:
j=1, i=2,此时s[j] != s[i],j回溯到next[j-1]直至s[j] == s[i]或者j = 0

- 第三步:
j=0, i=3, s[j] == s[i]

- 第四步:
j=1, i=4, s[i] == s[j]

*第五步:j=2, i=5, s[i]!=s[j],不断对j进行回溯

- 第一步:
Q
Q:字符串的结构和匹配
Q:前缀表
Q:前缀与后缀和最长公共前后缀
Q:BF算法及复杂度
Q:KMP算法思路
Q:next数组的概念
874

被折叠的 条评论
为什么被折叠?



