36 lines
1.2 KiB
Markdown
36 lines
1.2 KiB
Markdown
|
# KMP
|
||
|
|
||
|
[代码随想录](https://programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html)
|
||
|
|
||
|
KMP 主要用在 pattern 匹配上。
|
||
|
|
||
|
比如给出一个字符串 s 和一个 pattern ,请找出 pattern 第一次在 s 中出现的下标。
|
||
|
|
||
|
## 最长公共前后缀
|
||
|
|
||
|
前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串;
|
||
|
|
||
|
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
|
||
|
|
||
|
比如字符串 aaabcaaa 的最长公共前后缀是 aaa ,最长公共前后缀长度就是 3 。
|
||
|
|
||
|
## 前缀表
|
||
|
|
||
|
`next[i]` 表示 `s[0...i]` 这个子字符串的最长公共前后缀长度。
|
||
|
|
||
|
## 基本思路
|
||
|
|
||
|
`i` 代表 pattern 的前缀结尾,`j` 代表 s 的后缀结尾。
|
||
|
|
||
|
我们假设 `pattern[0...j]` 和 `s[i-j...i]` 一开始是相等的,但是当 `j` 和 `i` 都自增了 1 之后就不完全相等了,即末尾的 `pattern[j]` 和 `s[i]` 不相同。
|
||
|
|
||
|
但是 `pattern[0...j]` 有一段前缀 `pattern[0...k]` 和 `s` 的一段后缀 `s[i-k...i]` 相同。
|
||
|
|
||
|
那么我们可以从 `pattern[k+1]` 开始匹配。
|
||
|
|
||
|
这个时候我们需要让 `j` 回退到 `k+1` 。那么怎么做呢?
|
||
|
|
||
|
实际上 `k+1 == next[j-1]` 。
|
||
|
|
||
|
参考 s0028 详细代码实现与注释
|