acwing831kmp字符串(模板题)

先暴力:
for i遍历s每一点当起点
for j 从i到i+n-1
如果s[  i  ]!=p[ j ] break

但我们可以利用我们已经扫描过的s序列的信息看我们可以跳到p序列什么位置,使得p该位置之前和以扫描末尾段重合

板子如下:
#include <bits/stdc++.h>

using namespace std;

const int N=10005;
const int M=100005;
char p[N],s[M];
int ne[N],n,m;

int main(int argc, char** argv) {
	scanf("%d",&n);	scanf("%s",p+1);	scanf("%d",&m);	scanf("%s",s+1);
	//构造ne[] 
	for(int i=2,j=0;i<=n;i++){//i=1时不行,因为这样所有的ne就会等于自己本身,而我们要使不重的ne等于0(到头了) 
		while(j&&p[j+1]!=p[i]) j=ne[j];//要么到头了,要么j+1与i相等出来 ,到头了j=ne[j]=0 
		if(p[j+1]==p[i]) j++;//j+1(下一位)与i相等就更新下一位 
		ne[i]=j;//到头了j=0,不执行上if;如果是相等出来的就会执行上if,更新i的ne,即这段末尾与开头重合部分的末点 
	}
	
	for(int i=1,j=0;i<=m;i++){
		while(j&&p[j+1]!=s[i]) j=ne[j];//要么j到头了,要么满足下一个相等 ,每次ne都使j更小一点(相当于s序列前移) 
		if(p[j+1]==s[i]) j++;//如果下一个相等。j往下走 
		if(j==n){
			printf("%d ",i-n);//程序s序列从1开始,题从0开始所以要长度-1,而长度是当前i-p串长+1 
			j=ne[j];//j到头了,理论上重新开始,但可以ne节省 
		}
	}
	return 0;
}
假设一个点可有两个ne,那么ne记录的最长的那个:



全部评论

相关推荐

点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务