KMP未优化:

#include <iostream>
#include <string>
using namespace std;
/* P 为模式串,下标从 0 开始 */
void GetNext(string P, int next[])
{
int p_len = P.size();
int i = 0; // P 的下标
int j = -1;
next[0] = -1;
while (i < p_len - 1)
{
if (j == -1 || P[i] == P[j])
{
i++;
j++;
next[i] = j;
}
else
j = next[j];
}
}
/* 在 S 中找到 P 第一次出现的位置 */
int KMP(string S, string P, int next[])
{
GetNext(P, next);
int i = 0; // S 的下标
int j = 0; // P 的下标
int s_len = S.size();
int p_len = P.size();
while (i < s_len && j < p_len)
{
if (j == -1 || S[i] == P[j]) // P 的第一个字符不匹配或 S[i] == P[j]
{
i++;
j++;
}
else
j = next[j]; // 当前字符匹配失败,进行跳转
}
if (j == p_len) // 匹配成功
return i - j;
return -1;
}
KMP优化:

1 void GetNextval(string P, int nextval[])
2 {
3 int p_len = P.size();
4 int i = 0; // P 的下标
5 int j = -1;
6 nextval[0] = -1;
7
8 while (i < p_len - 1)
9 {
10 if (j == -1 || P[i] == P[j])
11 {
12 i++;
13 j++;
14
15 if (P[i] != P[j])
16 nextval[i] = j;
17 else
18 nextval[i] = nextval[j]; // 既然相同就继续往前找真前缀
19 }
20 else
21 j = nextval[j];
22 }
23 }
KMP算法(未优化版): next数组表示最长的相同真前后缀的长度,我们不仅可以利用next来解决模式串的匹配问题,也可以用来解决类似字符串重复问题等等,这类问题大家可以在各大OJ找到,这里不作过多表述。
KMP算法(优化版): 根据代码很容易知道(名称也改为了nextval),优化后的next仅仅表示相同真前后缀的长度,但不一定是最长(称其为“最优相同真前后缀”更为恰当)。此时我们利用优化后的next可以在模式串匹配问题中以更快的速度得到我们的答案(相较于未优化版),但是上述所说的字符串重复问题,优化版本则束手无策。
EXKMP:

1 void Get_Next(char *S, int *next) {
2 int lenS = strlen(S + 1), p = 1, pos;
3 next[1] = lenS; // 对于 next[1] 要特殊考虑
4 while (p + 1 <= lenS && S[p] == S[p + 1]) ++ p;
5 next[pos = 2] = p - 1; // next[2] 是为了初始化
6
7 For (i, 3, lenS) { // 注意此时 k + 1 = i
8 int len = next[i - pos + 1];
9 if (len + i < p + 1) next[i] = len; // 对应上面第一种情况
10 else {
11 int j = max(p - i + 1, 0); // 找到前面对于 子串 最靠后已经匹配的位置
12 while (i + j <= lenS && S[j + 1] == S[i + j]) ++ j; // 第二种需要暴力匹配
13 p = i + (next[pos = i] = j) - 1; // 记得更新 p, pos
14 }
15 }
16 }
17
18 void ExKMP(char *S, char *T, int *next, int *extend) {
19 int lenS = strlen(S + 1), lenT = strlen(T + 1), p = 1, pos;
20
21 while (p <= lenT && S[p] == T[p]) ++ p;
22 p = extend[pos = 1] = p - 1; // 初始化 extend[1]
23
24 For (i, 2, lenS) {
25 int len = next[i - pos + 1];
26 if (len + i < p + 1) extend[i] = len;
27 else {
28 int j = max(p - i + 1, 0);
29 while (i + j <= lenS && j <= lenT && T[j + 1] == S[i + j]) ++ j;
30 p = i + (extend[pos = i] = j) - 1;
31 }
32 } // 和上面基本一模一样啦
33 }
