KMP算法

本文深入解析KMP算法,一种高效的字符串匹配算法。通过对比暴力枚举法,介绍KMP算法如何利用next数组优化搜索过程,避免重复比较,提高匹配效率。文章详细解释了next数组的计算方法,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一开始感觉KMP算法非常难,但是其实多搜一些资料仔细研究一下发现其实。。

其实还是学习方法的问题吧,学的太潦草,不深入,仔细钻研,发现其实并不是那么难。

KMP算法是字符串匹配算法。

给定两个字符串a,b。统计串b在a中出现的位置与次数。

a= bacbababadababacambabacaddababacasdsd

b= ababaca

1.暴力枚举

bacbababadababacambabacaddababacasdsd

ababaca

每次让b串向后移一位。

bacbababadababacambabacaddababacasdsd

  ababaca

2.借助next数组来实现。

    KMP算法的核心也就在这个next数组上面。它主要存储了当匹配失败时,串b需要后移的位数。我们不单单是后移一位,我们预先处理出需要后移的位数,那么因为是预处理,所以next数组的计算也就和串a没有半毛钱关系。

next[j] = k.最关键的一条语句了。

假设现在有两个串,每个串从0开始存储:

S = ABCABCDHIJKOOL

T = ABCABB

在第5位发现匹配失败:

这时我们的移动方案:

S = ABCABCDHIJKOOL

T =        ABCABB

移动完后我们直接从T串的第C开始继续匹配就OK。

显然,我们不可能真正的去移动,我们需要用两个指针(l,r)去模拟。

第一次在第五位发现匹配失败时,l = 5, r= 5.

然后移动后l = 5, r = 2.

显然当匹配失败时,r要移动到下一个位置,而l是不动的。r要移动到第k位

我们观察上面的移动可以发现:

T串的前k个字符和r之前的最后k个字符相同,这里的r是指匹配失败时的r。

这里我们移动到了第2位,显然k=2.

T串的前2位:ABCABB

r之前的最后K位:ABCABB

显然r的取值范围是0~length(串的长度)-1。

我们用一个next数组来保留每一个r需要后移的位数K。

 

4.计算next数组。

next数组的计算只需要用到T串。

我们可以利用一种dp的思想来处理。

依然用这个串T = ABCABBC

我们先考虑j=0时,这个时候r无法移动,只能右移l。所以初始化为-1,即next[0] = -1;

再考虑j = 1,r只能移动到第0位。next[1] = 0;

j  = 2,T[0] != T[1], next[2] = 0;

j = 3, next[3] = 0;
j =  4, next[4] = 1;

j = 5, next[5] = 2;

我们在计算next[5] 时显然可以利用next[4],因为T[j - 1] == T[next[j - 1]], 所以next[j] = next[j - 1] + 1.

那么

    next[0] = -1;
	int j = 0, k = -1;
	while(j < m - 1){
		if(k == -1 || T[j] == T[k]){
			next[++j] = ++k;
		} else k = next[k];
	}

显然当T[j - 1] != T[k]时, next[j] = 0; 

k = next[k] :

看这个串:ABACDABABC, C是第九位,此时k = 3, j =  8.(ABA)

此时C != B,  k = next[3], 这里next[3]>0,j的前面有部分和整串的前缀相同, 所以我们可以直接把T[next[k]]和T[j]比较。

再看ABAB这个串,显然next[3] = 1;但是我们真的有必要从1再比较吗?没必要,因为T[1] = T[3]。

所以,上述代码可以再优化一下:

next[0] = -1;
	int j = 0, k = -1;
	while(j < m - 1){
		if(k == -1 || T[j] == T[k]){
			if(T[++j] == T[++k]) next[j] = next[k];
			 else next[j] = k;
		} else k = next[k];
	}

5.KMP比较

最后一步了,拿两个指针去模拟就行了。

#include<cstdio>
#include<cstring>
int n, m, l, r, k, ans;
char S[120], T[120];
int next[120];
int main(){
	scanf("%s%s", S, T);
	n = strlen(S);
	m = strlen(T);
	next[0] = -1;
	int j = 0, k = -1;
	while(j < m - 1){
		if(k == -1 || T[j] == T[k]){
			if(T[++j] == T[++k]) next[j] = next[k];
			 else next[j] = k;
		} else k = next[k];
	}
	l = 0; r = 0;
	while(l < n && r < m){
		if(r == -1 || S[l] == T[r]){
			l++;
			r++;
		}else r = next[r];
		if(r == m){
			printf("%d ", l - r);
			ans++;
			r = 0;
		}
	}
	printf("\n%d", ans);
	return 0;
}

 

 

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称描述,点击“确”。 在Pipeline脚本中义项目字典、发版脚本预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于义自动化构建发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,义了四个阶段:Checkout、Build、Push packageDeploy/Rollback。每个阶段都可以根据实际需求进行配置调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率项目质量。借助Pipeline,我们能够轻松实自动化构建、测试部署,从而提高项目的整体质量可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值