这是第二次学KMP了,第一次是在数据结构课上,当时理解了好久,没想到第二次学还是这么费劲,果然还是太菜了。
AcWing 831. KMP字符串
给定一个模式串S,以及一个模板串P,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模板串P在模式串S中多次作为子串出现。
求出模板串P在模式串S中所有出现的位置的起始下标。
输入格式
第一行输入整数N,表示字符串P的长度。
第二行输入字符串P。
第三行输入整数M,表示字符串S的长度。
第四行输入字符串S。
输出格式
共一行,输出所有出现位置的起始下标(下标从0开始计数),整数之间用空格隔开。
数据范围
1≤N≤105
1≤M≤106
输入样例:
3
aba
5
ababa
输出样例:
0 2
注意:
这是多次匹配,且涉及到共用部分:
输入
3
aba next值:0 0 1
5
ababa
输出
0 2 ,涉及到了共用,共用了s[3]的a (从下标1存储)
代码实现
为了便于理解,模板串P和模式串S都从下标1开始存储,然后在输出时下标-1即可。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=1e6+10;
int Next[N];
char s[M],p[N];//字符型数组,注意下面是怎么从下标1处输入数据的
int main()
{
int n,m;
cin>>n>>p+1>>m>>s+1;//cin自动过滤回车 空格;从下标1开始存储数据
//求Next数组,Next[1]=0,默认
for (int i = 2,j=0; i <= n; ++i) {
while (j && p[i]!=p[j+1]) j=Next[j];
if (p[i]==p[j+1]) j++; //判断上面退出while循环的原因,是否成功匹配了一位
Next[i]=j;
}
//KMP匹配过程
for (int i = 1,j=0; i <= m; ++i) {
while (j && s[i]!=p[j+1]) j=Next[j]; //当一次匹配成功后,开始下一次匹配,涉及到共用前面的部分,而j+1和i的匹配一定失败,所以开始回退
if (s[i]==p[j+1]) j++;
if (j==n){
printf("%d ",i-j);//输出时,记得把下标转换成相对于0位置存储的
j=Next[j]; //提前执行一下23行的语句,因为要去掉if语句,防止越界
} //因为p[n + 1] == '\0',它和s[]中的任何一个字符都不匹配,所以这里写不写都可以。但建议写上,避免以后出现边界问题。
}
return 0;
}
新思路传送:
字符串哈希