KMP算法
KMP算法——用于字符串匹配。优点是在匹配的过程中不用回退主指针,子指针会根据子串中最长相等前后缀来进行回退,能够大大降低时间复杂度。
这里有几个定义需要说明:
- 前缀:不包含尾字符的所有子串
- 后缀:不包含首字符的所有子串
举例:T = aabaaf
| 子串 | 说明 | 最长相等前后缀的长度 |
|---|---|---|
| $t_1=\mathrm{a}$ | 无前缀也无后缀 | $\pi \left( 0 \right) =0$ |
| $t_1=\mathrm{aa}$ | 前缀为$\small{\mathrm{a}}$后缀也为$\small{\mathrm{a}}$ | $\pi \left( 1 \right) =1$ |
| $t_1=\mathrm{aab}$ | 前缀一定无$\small{\mathrm{b}}$后缀一定有$\small{\mathrm{b}}$ | $\pi \left( 2 \right) =0$ |
| $t_1=\mathrm{aaba}$ | 最大相等前后缀为$\small{\mathrm{a}}$ | $\pi \left( 3 \right) =1$ |
| $t_1=\mathrm{aabaa}$ | 最大相等前后缀为$\small{\mathrm{aa}}$ | $\pi \left( 4 \right) =2$ |
| $t_1=\mathrm{aabaaf}$ | 无最大相等前后缀 | $\pi \left( 5 \right) =0$ |
| $\mathrm{j}$ | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| $T$ | a | a | b | a | a | f |
| $\pi(T)$ | 0 | 1 | 0 | 1 | 2 | 0 |
一般也把$\small{\pi(T)}$叫做前缀表,前缀表中保存的元素就是子指针回退的位置。编程实现中,也叫 next 数组。具体计算如下:
1 | void NextTable(vector<int>& next, string s) |
力扣 28
找出字符串中第一个匹配项的下标
这个题目就是一道经典的匹配问题,暴力解法同时遍历 haystack 和 needle,时间复杂度为$\small{O(M*N)}$,空间复杂度为$\small{O(1)}$:
1 | int strStr(string haystack, string needle) |
如果用 KMP 算法,时间复杂度为$\small{O(M+N)}$,空间复杂度为$\small{O(M)}$。
1 | int strStr(string haystack, string needle) |
可以发现 KMP 算法无论是创建前缀表还是应用前缀表,代码具有高度相似性。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 洛天的小窝!
评论






