KMP算法学习笔记

本文详细介绍了KMP(Knuth-Morris-Pratt)字符串匹配算法,通过降低时间复杂度从O(m*n)到O(m+n)提高效率。文章阐述了KMP算法的核心思想,包括next数组的计算和利用最长相等前后缀解决失配问题。提供了代码实现,并通过示例解释了算法的运行过程,适合想要深入理解字符串匹配算法的读者。
摘要由CSDN通过智能技术生成

为什么要学它?

因为字符串问题匹配用它,相比暴力,复杂度可以从O(m*n)降到O(m+n),而且其中求最长相等前后缀的方法可以解决很多问题。

介绍一下字符串匹配:给出两个字符串a和b,要找出在a中的b。

如a为:abcacabcab,b为:abcab

正常暴力是逐位匹配,但是这样在每一次失配后都要重新匹配,这会增加很多的时间复杂度。

而KMP算法就可以减少损失的时间复杂度,因为KMP算法在每一次失配后不会重新匹配,而会跳到更优的位置(b的位置)匹配。

而这个更优的位置怎么求?这就要引入一个新的数组,即为next(实际上为了避免编译时出现的奇奇怪怪的bug经常写成“nxt”)。该next[i]即为在b匹配到第i个字符时失配时应从b的哪个位置开始继续匹配。

例如上述例子,匹配到如下(加粗字母b)时失配:

abcacabcab

abcab

我们可以不从头开始匹配,而是从如下开始继续匹配(b中的'a'和中的'a'对齐(已加粗)):

abcacabcab

      abcab

这样即为next[5]=1

那么,这个next数组应该怎么求呢?

这就要引用上文提到的最长相等前缀和了。

为什么要利用它?因为当我们如果匹配到第i位时失配,第i位之前的信息我们都是知道的,所以我们可以通过处理b数组的第i位之前的字符,来得到失配后该从哪里重新开始匹配。显然,我们可以利用b的前i-1位的最长相等前后缀和来判断,这个模拟一下就可以理解,也可以参照上面失配时的示范。

如何用代码实现?可以用b自己匹配自己,这个不太好理解,就在代码里注释了,如下:

p=0;
for(int i=2;i<=lenb;i++)
{
	while(b[i]!=b[p+1]&&p)	p=next[p];//失配就往回跳,直到可以匹配
	if(b[i]==b[p+1])	p++;//匹配成功,则+1
	next[i]=p;//记录next数组
}

这段代码如果不理解可以输出一下来帮助理解。

next数组求完后,就可以按之前说的步骤进行了。

代码如下:

p=0;
for(int i=1;i<=la;i++)
{
	while(a[i]!=b[p+1]&&p)	p=next[p];//不断跳next直到能匹配
	if(a[i]==b[p+1])	p++;
	if(p==lb)//匹配成功
	{
        ans++;//统计结果
		p=next[p];
	}
}

这样KMP就完成了。

洛谷的模板题可以做一下传送门

(附上这道题的代码)

#include<bits/stdc++.h>
using namespace std;

char a[1000005],b[1000005];
int next[1000005],p;
int main()
{
	cin>>a+1>>b+1;
	int la=strlen(a+1),lb=strlen(b+1);
	for(int i=2;i<=lb;i++)
	{
		while(b[i]!=b[p+1]&&p)	p=next[p];
		if(b[i]==b[p+1])	p++;
		next[i]=p;
	}
	p=0;
	for(int i=1;i<=la;i++)
	{
		while(a[i]!=b[p+1]&&p)	p=next[p];
		if(a[i]==b[p+1])	p++;
		if(p==lb)
		{
			cout<<i-lb+1<<endl;
			p=next[p];
		}
	}
	for(int i=1;i<=lb;i++)	cout<<next[i]<<" ";
	return 0;
}

感谢这位大佬的这篇博客

(蒟蒻的第二篇,求支持qwq)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值