P3375 【模板】KMP字符串匹配

题目描述

如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。

为了减少骗分的情况,接下来还要输出子串的前缀数组next。

(如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了。)

输入输出格式

输入格式:

第一行为一个字符串,即为s1(仅包含大写字母)

第二行为一个字符串,即为s2(仅包含大写字母)

输出格式:

若干行,每行包含一个整数,表示s2在s1中出现的位置

接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值。

输入输出样例

输入样例#1: 复制
ABABABC
ABA
输出样例#1: 复制
1
3
0 0 1 

说明

时空限制:1000ms,128M

数据规模:

设s1长度为N,s2长度为M

对于30%的数据:N<=15,M<=5

对于70%的数据:N<=10000,M<=100

对于100%的数据:N<=1000000,M<=1000000

样例说明:

所以两个匹配位置为1和3,输出1、3


复习了下kmp

这题和裸kmp唯一的区别是当匹配成功之后,还要再沿着失配边回去,继续与之后的字符匹配。

#include
#include
#include
#include
using namespace std;
const int MAXN = 1000000;
typedef long long LL;
typedef double DB;
inline int get(){
	char c;
	while((c = getchar()) < '0' || c > '9');
	int cnt = c - '0';
	while((c = getchar()) >= '0' && c <= '9') cnt = cnt * 10 + c - '0';
	return cnt;
}
char s1[MAXN + 10],s2[MAXN + 10]; 
int next[MAXN + 10];
int main(){
	#ifdef lwy
		freopen("1.txt","r",stdin);
/*	#else
		freopen(".in","r",stdin);
		freopen(".out","w",stdout);*/ 
	#endif
	scanf("%s",s1); scanf("%s",s2);
	int len1 = strlen(s1);
	int len2 = strlen(s2);
	next[0] = next[1] = 0;
	for(int i = 1; i < len2; i ++){
		int j = next[i];
		while(j && s2[i] != s2[j]) j = next[j];
		if(s2[i] == s2[j]) next[i + 1] = j + 1;
		else next[i + 1] = 0; // i -> i + 1 
	}
	int k = 0;
	for(int i = 0; i < len1; i ++){
		while(k && s1[i] != s2[k]) k = next[k];
		if(s1[i] == s2[k]) k ++;
		if(k == len2){
			printf("%d\n",i - k + 2);
			k = next[k];
		} 
	}
	for(int i = 1; i <= len2; i ++){
		printf("%d ",next[i]);
	}
	return 0;
}




你可能感兴趣的:(kmp,模板)