KMP
KMP算法的核心是当前位失配时,可以跳转当上一个最长的匹配位置
模式串:abcab
文本串:abcacababcab
当第 5 位失配时应当直接跳转到第一位
实现
-
当前位匹配,模式串匹配长度 + 1
-
当当前位失配时,
跳转到当前 前缀的 前缀和后缀 最大匹配位置
并验证当前位是否匹配,否则重复以上过程
ps:如果持续失配,跳转到第一位,重新开始匹配
void Kmp(int len, int max_len) { //匹配串长度和模式串长度
int j = 0;
for (int i = 1; i <= len; i++) {
while (j && s[i] != p[j + 1])j = kmp[j];
//如不匹配,持续跳转,直到下一位匹配或者跳到最开始为止
//此时j存储的时上一个匹配成功的位置
if (s[i] == p[j + 1])j++;
//匹配,匹配长度加一
//此时j存储的是当前匹配成功的位置
if (j == max_len) { //完全匹配
cout << i - max_len + 1 << '\n';
j = kmp[j]; //继续跳转,重新开始
}
}
}
Kmp数组
Kmp[i] 表示第一个到第 i-1 个字符串的前缀和后缀最长匹配长度
- Kmp的求法即为自己与自己匹配
当前位与模式串最大匹配长度即为前缀与后缀最长匹配长度
由2 开始是因为前缀位{ 1 - i },后缀为{ j - i + 1 ,j},要保持 i > = 1
例如{a1,a2,a3,a4}最大匹配为{a1,a2,a3}和{a2,a3,a4}
所以匹配串为由第二位开始的模式串 - 由于 j 是小于 i 的,所以正确性是显然的
void Get_Kmp(int len) { //模式串长度
kmp[0] = kmp[1] = 0;//初始化
int j = 0;
for (int i = 2; i <= len; i++) {
while (j && p[i] != p[j + 1])j = kmp[j];
//如不匹配,持续跳转,直到下一位匹配或者跳到最开始为止
if (p[i] == p[j + 1])j++;
//匹配,匹配长度加一
kmp[i] = j;
//记录kmp,当前串和模式串最大匹配距离
}
}