KMP算法之匹配过程详解——结构、原理与C++实现
学会构建 next 数组后,匹配过程就很简单,可以参照这篇博客。
KMP 利用已经部分匹配的信息,避免重复匹配,提高了字符串匹配的效率,时间复杂度是 $ O(n + m) $ ,其中 n 是主串长度,m 是模式串长度。
使用 next 数组做匹配
在文本串 s 里找是否出现过模式串 t 。定义两个下标 j 指向模式串起始位置, i 指向文本串起始位置。
那么 j 初始值为 0 , 因为 next 数组里记录的起始位置为 0。
i 就从0开始,遍历文本串,代码如下:
1 | for (int i = 0; i < s.size(); i++) |
接下来就是 s[i] 与 t[j] (因为 j 从 0 开始的) 进行比较。
如果 s[i] 与 t[j] 不相同,j 就要从 next 数组里寻找下一个匹配的位置。
代码如下:
1 | while(j > 0 && s[i] != t[j]) { |
如果 s[i] 与 t[j] 相同,那么 i 和 j 同时向后移动, 代码如下:
1 | if (s[i] == t[j]) { |
如何判断在文本串 s 里出现了模式串 t 呢,如果 j 指向了模式串 t 的末尾,那么就说明模式串 t 完全匹配文本串 s 里的某个子串了。
完整代码
1 | int j = 0; // 因为next数组里记录的起始位置为0 |
示例
文本串 s = "abcabcababac"
模式串 t = "ababac"
第一步:构造 next 数组
| i | t[i] | j(前缀指针) | 比较 | next[i] |
|---|---|---|---|---|
| 1 | b | 0 | a ≠ b | 0 |
| 2 | a | 0 | a = a | 1 |
| 3 | b | 1 | b = b | 2 |
| 4 | a | 2 | a = a | 3 |
| 5 | c | 3 | b ≠ c → 回退 j=next[2]=1 → a ≠ c → j=0 | 0 |
最终: next = [0, 0, 1, 2, 3, 0]
第二步:匹配过程
文本串 s = "abcabcababac"
模式串 t = "ababac"
初始状态:i = 0, j = 0
i |
s[i] |
t[j] |
匹配 | j 变化—-本轮执行后 j 的值 |
说明 |
|---|---|---|---|---|---|
| 0 | a | a | 是 | j=1 | 首字符匹配 |
| 1 | b | b | 是 | j=2 | |
| 2 | c | a | 否 | j=0 | 回退 j = next[j - 1] = next[1] = 0 |
| 2 | c | a | 否 | j=0 | 继续下一轮匹配 |
| 3 | a | a | 是 | j=1 | |
| 4 | b | b | 是 | j=2 | |
| 5 | c | a | 否 | j=0 | 再次失败,回退 |
| 6 | a | a | 是 | j=1 | |
| 7 | b | b | 是 | j=2 | |
| 8 | a | a | 是 | j=3 | |
| 9 | b | b | 是 | j=4 | |
| 10 | a | a | 是 | j=5 | |
| 11 | c | c | 是 | j=6 | 完全匹配成功 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 chengoasis!



