这个巨巨讲的简单易懂:
KMP 算法详解 - AcWing
配合动画更易理解:
KMP模式搜索算法动画演示
KMP是一种高效的字符串匹配算法,用来在主字符串中查找模式字符串的位置(如:在字符串“Hello,world!”中查找“world”模式串的位置)
例题:
给定一个模式串 S 长度为 M ,以及一个模板串 P 长度为 N ,所有字符串中只包含大小写英文字母以及阿拉伯数字。 模板串 P 在模式串 S 中多次作为子串出现。 求出模板串 P 在模式串 S 中所有出现的位置的起始下标。(N <= 1e5 && M <= 1e6)
输入样例:
3 aba 5 ababa
输出样例:
0 2
文章中next数组就是KMP算法省时的关键。
next[]数组的性质:
next [ i ] 表示模式串P中以 i(下表从 i 开始)结尾的后缀(能匹配的P的前缀的最大长度)。
next [ i ] = j,表示 P [ i - j + 1,i ]
上面acwing的那篇文章已经把KMP讲得很具体了,我来给出一个从i=0开始的模板。
以 i=0 开始的预处理 next 的模板:
memset(next,0,sizeof (next));
for (int i=1,j=0;i<n;i++) {
while (j&&p[i]!=p[j]) j=next[j]; //i,j指的值不等时,不断寻找之前的值
if (p[i]==p[j]) j++; //当i,j指的值相等时,j+1,准备进行下一值的比较
next[i+1]=j;
}
以 i=0 开始的KMP模板:
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int M=1e6+5;
int next[M];
char p[M],a[M];
int main() {
int t; cin>>t;
while (t--) {
int sum=0;
scanf("%s%s",&p,&a); //p--要找的串 a--大串
//p预处理
int lenp=strlen(p),lena=strlen(a);
for (int i=1,j=0;i<lenp;i++) {
while (j&&p[i]!=p[j]) j=next[j];
if (p[i]==p[j]) j++;
next[i+1]=j;
}
for (int i=0,j=0;i<lena;i++) {
while (j&&p[j]!=a[i]) j=next[j];
if (p[j]==a[i]) j++;
if (j==lenp) {
j=next[j];
sum++;
}
}
printf("%d\n",sum);
memset(a,0,sizeof a);
memset(p,0,sizeof p);
memset(next,0,sizeof next);
}
return 0;
}