KMP 算法是一种优秀的字符串模式匹配算法,相对于暴力匹配方法来说,其改进在于:每当一趟匹配过程出现字符比较不相等时,不需回溯主串的 iii 指针,而是利用已经得到的「部分匹配」的结果将模式串向右「滑动」尽可能远的一段距离后(即回溯模式串的 jjj 指针),继续进行比较。
\begin{array}{c} next[j] = \begin{cases} -1 & j = 0 \\ k & if \ p_{k} \ne p_{j} \\ next[k] & if \ p_{k} = p_{j} \end{cases} \end{array}
计算失配数组时间复杂度 O(m),主串与模式串匹配时间复杂度 O(n),故 KMP 算法总的时间复杂度为 O(n+m) 。
#include <bits/stdc++.h>
using namespace std;
#ifndef _KMP_
#define _KMP_
#define ll int
#define MAXN 1000005
#define MAXM 1000005
// KMP 算法
struct KMP {
// 失配数组
// next[j] 表示当模式中第 j 个字符与主串字符失配时
// 模式串中失配位置需要滑动到的位置
ll next[MAXM];
vector <ll> match;
KMP() {}
// 计算失配数组
void getNext(char *pattern, ll m) {
// pattern 模式串
next[0] = -1;
ll i = 0, j = -1;
while(i < m) {
if(!(~j) || pattern[i] == pattern[j]) {
++i, ++j;
if(pattern[i] != pattern[j]) next[i] = j;
else next[i] = next[j];
} else {
j = next[j];
}
}
}
// 计算模式串在主串中第 pos 个字符后出现首个匹配的首位置
ll getIndex(ll pos, char *main, ll n, char *pattern, ll m) {
ll i = pos, j = 0;
while(i < n && j < m) {
if(!(~j) || main[i] == pattern[j]) {
++i, ++j;
} else {
j = next[j];
}
}
if(j < m) {
return -1;
}
return i - m;
}
// 计算模式串在主串中所有匹配的首位置
void getIndexs(char *main, ll n, char *pattern, ll m) {
ll i = 0, j = 0;
while(i < n) {
if(!(~j) || main[i] == pattern[j]) {
++i, ++j;
if(j == m) {
j = next[j];
match.push_back(i-m);
}
} else {
j = next[j];
}
}
}
};
#endif