C角度(一)——任何C程序,可理解为指针指向某一个字符,然后字符匹配
上述代码直观地体现了“指针指向字符、逐字符比较、失配后回溯”的过程。
3. KMP 算法:引入记忆的匹配
3.1 为什么需要 KMP
暴力匹配的核心缺陷在于每次失配后都从头开始,导致大量重复比较。KMP 通过预处理目标串 T,构造一个部分匹配表(next 数组),记录在失配时可以“跳过”的字符数,从而避免不必要的回溯。
3.2 部分匹配表(next 数组)概念
next[i] 表示子串 T[0..i] 的最长相等前后缀的长度。例如,对于 T = "abcabd":
| i | T[i] | 前缀 | 后缀 | longest prefix = suffix | next[i] |
|---|---|---|---|---|---|
| 0 | a | - | - | 0 | 0 |
| 1 | b | a | b | 0 | 0 |
| 2 | c | ab | bc | 0 | 0 |
| 3 | a | abc | cab | 0 | 0 |
| 4 | b | abca | abc | 2 (ab) | 2 |
| 5 | d | abcab | bcab | 0 | 0 |
(实际实现中 next[0] 通常设为 -1,便于统一处理失配后的跳转逻辑。)
3.3 KMP 匹配流程
- 构造 next 数组(时间 O(n))。
- 使用两个指针
i(遍历 S)和j(遍历 T)。 - 当
S[i] == T[j]时,i++、j++。 - 若失配且
j > 0,则j = next[j-1](利用记忆跳转),而i不变。 - 若失配且
j == 0,则仅i++(直接向后移动 S 的指针)。 - 当
j == n时,匹配成功,返回i - n。