Acwing831. KMP字符串

题目地址
在这里插入图片描述
求next[j] ,最大的后缀和前缀相等长度是多少
在这里插入图片描述

kmp中next[j]数组的含义
模板串s: 起点为1, 终点为i
next[j] 代表前半段匹配的子串长度和后半段匹配的子串长度相同且长度最大的 子串。最大的后缀等于前缀。
后缀和前缀

在这里插入图片描述i从下标1开始,j从下标0开始。
因为模式串和模板串匹配的位置是s[i] 和p[j+1],往前错一位

//i 代表模式串s下标,j代表模板串p下标,两个下标要错一位
	// KMP匹配过程
	for(int i=1,j=0;i<=m;i++){
		while(j!=0 &&p[j+1]!=s[i]){  //1.判断j往前倒退,看是否能退, 2.判断判断j能不能往后走
			j=ne[j]; //如果j不能往后走,就往前退一步。退一步之后再循环判断能不能往后走
		}
		// while结束循环有两种条件 1.模板串j下标退无可退了 2.匹配成功 
		//如果匹配了,j可以往后挪一个位置
		if(s[i]==p[j+1]){
			j++;
		}
		if(j==n){
			// 说明匹配成功
		}
	}
	

kmp就是往前退一步
j=ne[j]
j=ne[ne[j]]
j=ne[ne[ne[j]]

	//求next过程
	for(int i=2,j=0;i<=n;i++){
		while(j&& p[i]!=p[j+1]){ //模板串自己和自己对比,找最大前缀
			j=ne[j];
		}
		if(p[i]==p[j+1]){
			j++;
		}
		ne[i]=j;
	}

举例:

在这里插入图片描述令j=ne[j] 重新开始匹配,继续做
在这里插入图片描述整体代码:

#include<iostream>
using namespace std;
const int N = 10010, M = 100010;
int n, m;
char p[N], s[M]; // 字符串
int ne[N];

int main() {
//	string p,s;
	cin >> n >> p + 1 >> m >> s + 1;
	//求next过程
	for (int i = 2, j = 0; i <= n; i++) {
		while (j && p[i] != p[j + 1]) { //模板串自己和自己对比,找最大前缀
			j = ne[j];
		}
		if (p[i] == p[j + 1]) {
			j++;
		}
		ne[i] = j;
	}

	//i 代表模式串s下标,j代表模板串p下标,两个下标要错一位
	// KMP匹配过程
	for (int i = 1, j = 0; i <= m; i++) {
		while (j && p[j + 1] != s[i]) { //1.判断j往前倒退,看是否能退, 2.判断判断j能不能往后走
			j = ne[j]; //如果j不能往后走,就往前退一步。退一步之后再循环判断能不能往后走
		}
		// while结束循环有两种条件 1.模板串j下标退无可退了 2.匹配成功
		//如果匹配了,j可以往后挪一个位置
		if (s[i] == p[j + 1]) {
			j++;
		}
		if (j == n) {
			// 说明匹配成功
			// 题目要求输出匹配成功的起始位置
			cout << i - n << endl;
			j = ne[j]; //匹配成功后再往后退一步,
		}
	}



	return 0;
}

举例:
在这里插入图片描述在这里插入图片描述j=ne[6]=4;再从这个位匹配。

看不懂,就背下来代码吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值