KMP
字符串查找算法:在文本串S中查找模式串P
推荐初学者先看这篇大佬博客,讲的超级详细从头到尾彻底理解就KMP
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 1000010;
int m, n;//m是S的长度,n是P的长度
char s[N], p[N];
int ne[N];
//ne[i]表示,在字符串p里,下标为i的字符(第i+1个字符)之前字符串的公共前缀和后缀的最大长度
void KmpSearch(int m, int n, char* p, char* s) {
int i = 0;
int j = 0;
int k = -1;//前缀后缀公共元素的个数
ne[0] = -1;//设定初始值
//第一个元素前面没有字符,设为1,
//第二个元素前面只有一个元素不存在前缀后缀,所以是0
int slen = m;
int plen = n;
//求next数组
//即p字符串自我匹配的过程
//j是后缀的下一位,k是前缀的下一位
/*假设 ne[j]=k j前面字符串的公共前后缀最大长度为k
若p[j] == p[k] 公共长度加一
ne[++j]=++k;
若p[j]!=p[k] j,k位置失配,那么公共前缀缩短,k回溯到某个位置重新和j处进行匹配,看下面图一
*/
while (j < plen ) {
if (k == -1 || p[j] == p[k]) {
j++;
k++;
ne[j] = k;//不优化
}
else
k = ne[k];
}
//kmp
j = 0;//清零为kmp做准备
while (i < slen && j < plen) {
//如果j==-1,或者当前字符匹配成功,都令i++,j++
if (j == -1 || s[i] == p[j]) {
j++;
i++;
}
//匹配不成功,此时的j在公共后缀的下一位,ne[j]是公共前缀的后一位
//j回调到ne[j]的位置,让ne[j]位置的数和s[i]继续匹配
//回调匹配的过程相当于字符串向右移动了 j-ne[j] 个位置
//即 失配时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next值
//与求ne[]数组不匹配那里同理,可以自己尝试画图
else {
j = ne[j];
}
//p串走到最后匹配成功,输出开始匹配的位置
if (j == plen)
{
printf("%d ", i - j);
j = ne[j];//因为P在S中出现的位置可能有重叠,所以需要回调
}
}
}
int main() {
cin >> n >> p >> m >> s;
KmpSearch(m, n, p, s);
return 0;
}
图一:求next数组,出现不匹配情况时, k = ne[k] 语句的图解