KMP 算法
概述
KMP 算法全称是 Knuth-Morris-Pratt 字符串查找算法,是用于在一个字符串(匹配串)中查找另一个字符串(模式串)的快速算法
KMP算法会在匹配前预处理模式串 P P P 得到 fail
数组, 借助 fail
数组,可以在匹配过程中减少很多冗余的操作,时间复杂度 : O ( n + m ) \mathcal{O}(n + m) O(n+m), 其中, n n n 和 m m m 是两个串的长度
算法流程
fail 数组的预处理
KMP 算法的核心是 fail
数组,对于字符串 s = s 0 , s 1 , s 2 , … , s n − 1 s = s_{0},s_{1},s_{2},\dots,s_{n - 1} s=s0,s1,s2,…,sn−1 ,如果 j j j 满足 s 0 … i = s i − j … i s_{0 \dots i} = s_{i - j \dots i} s0…i=si−j…i 的最大值,则 f a i l [ i ] = j fail[i] = j fail[i]=j 注意: j ≤ i j \le i j≤i 其中, s a … b s_{a \dots b} sa…b 表示字符串 s s s 从 a a a 号位到 b b b 号位的子串
对于不存在 s 0 … i = s i − j … i s_{0 \dots i} = s_{i - j \dots i} s0…i=si−j…i 的最大值,fail[i] = -1
对于字符串 “aababaab
” 则 fail
值如下:
匹配过程
对于上面的过程,当 a
和 ?
比较时失败了,那么我们要把母串的起始位置移动到下一个位置,对于 2 2 2 指向的匹配,这时候我们没必要从头开始比较,因为我们知道 fail[i] = 1
如果红色块可以完美匹配,那么应该等于 4 4 4 , 第 3 3 3, 4 4 4 次也是同理,所以直接跳到匹配 %5%
这就是 KMP 的本质:利用已经计算过了的信息加速匹配过程
代码
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 100;
int fail[maxn];
void getFail(char *P) {
int m = strlen(P);
fail[0] = -1;
for (int i = 1; i < m; ++i) {
int j = fail[i - 1];
while (j >= 0 && P[j + 1] != P[i]) {
j = fail[j];
}
if (P[j + 1] == P[i]) {
j++;
}
fail[i] = j;
}
}
int KMP(char *T, char *P) {
int n = strlen(T), m = strlen(P);
int j = -1;
for (int i = 0; i < n;