洛谷P3375:【模板】KMP字符串匹配
题目描述
如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。
为了减少骗分的情况,接下来还要输出子串的前缀数组next。
输入输出格式
- 输入格式:
第一行为一个字符串,即为s1
第二行为一个字符串,即为s2 - 输出格式:
若干行,每行包含一个整数,表示s2在s1中出现的位置
接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值。
输入输出样例
- 输入样例1:
ABABABC
ABA - 输出样例#1:
1
3
0 0 1
数据规模:
N<=1000000,M<=1000000
样例说明:
源代码
#include <iostream>
#include <cstdio>
#include <string>
#define MAXN 1000005
using namespace std;
int nex[MAXN];//前缀数组,记录str2的各个子串最长相同前后缀的长度
string str1,str2;
int j=0;
int main()
{
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
cin>>str1>>str2;
int len1=str1.length();
int len2=str2.length();
for(int i=1;i<len2;i++)//len1==0
{
//j表示当前子串已匹配的长度
while(j&&str2[j]!=str2[i])
j=nex[j-1];
//如果j与i不等,j跳回到与上一个相匹配点的下一个,再看等不等
//直到等或者j==0
//如果上一个子串的匹配长度为j且下一位相等,则匹配长度为j+1;
if(str2[i]==str2[j])
j++;
nex[i]=j;
//记录下第i个子串相匹配前后缀的长度
}
//以上为预处理
j=0;
for(int i=0;i<=len1;i++)//从头到尾遍历str1
{
while(j&&str1[i]!=str2[j])//碰到不一样的往回跳
j=nex[j-1];
if(str1[i]==str2[j])//一样就往前进
j++;
if(j==len2)//进到满就输出
{
cout<<i-len2+2<<endl;
j=nex[j-1];//输出完回到前后缀相同的下一个处(继续循环判断)
}
}
for(int i=0;i<len2;i++)//题目要求,输出next数组
cout<<nex[i]<<" ";
return 0;
}