浅学KMP算法

本cg在学习了kmp算法之后感叹道这个算法的奇妙之处,网上有很多关于其的原理,这里我就不再赘述了,但是直接了当的kmp代码确实是很少,所以为了帮助各位提高效率和自己巩固写了这篇文章。

首先还是说一下kmp算法是干什么的吧,kmp算法是用来找字串的,算是数据结构中的难点了,理解起来也比较费劲,有人就说了,学这干什么,不如直接substr。nonono,stl大法虽好,可不能贪杯啊,kmp算法即是高效找字串的方法,一般的方法发现不匹配之后就直接回到起始,大大降低了效率,但此算法不同,可以记住最近的匹配点,提高效率,好了,废话不多说,直接上代码

 

#include<iostream>
#include<string>
using namespace std;
int nexts[2000000];
void getnext(string s)
{
	nexts[0]=0;
	int i=1,j=0;
	while(i<s.length())
	{
		if(j==0||s[j]==s[i])
			nexts[++i]=++j;
		else
			j=nexts[j];
	}
}
int nextval[200005];
void getnextval(string s)
{
	int i=1;
	nextval[0]=0;
	while(i<s.length())
	{
		int index=nexts[i];
		if(s[i]==s[index])
			nextval[i]=nextval[index];
		else
			nextval[i]=nexts[i];
		i++;
	}
}
bool kmp(string s1,string s2)
{
	int i=0,j=0;
	getnext(s2);getnextval(s2);
	while(i<s1.length()&&j<s2.length())
	{
		if(j==0||s1[i]==s2[j])
		{
			i++;j++;
		}
		else
		{
			j=nextval[j];
		}
	}
	if(j>=s2.length())
		return true;
	else
		return false;

}

int main()
{
	int n;cin>>n;
	string s1,s2;cin>>s1>>s2;
	s1+=s1;
	if(kmp(s1,s2))
		cout<<"wow"<<endl;
	else
		cout<<"TAT"<<endl;

return 0;
}

如果是为了拿板子的话,可以润了,别忘了点个赞。

接下来,分析一下代码,kmp最关键的即使next数组和nextval数组的构建,浅显的讲一下next数组和nextval的构建,nextval可以理解为next的升级办,提高了原有的效率。

首先next数组,一般我们从下标为0开始,并将其定义为0.然后从字符串的下标为0,next数组的下标为1,开始,然后next数组的值即为字符串此下标前的字符相同前后缀的长度加1,比如aabaab,当前字符下标为5的时候,前面有五个字符,前后缀的最大相同长度为2,则此next数组的值为2+1=3。以此类推,因为第一个字符前面没有东西,所以将next【0】定义为0.

来看getnext

void getnext(string s)
{
	nexts[0]=0;
	int i=1,j=0;
	while(i<s.length())
	{
		if(j==0||s[j]==s[i])
			nexts[++i]=++j;
		else
			j=nexts[j];
	}
}

记录i为next数组开始下标,j为next数组的值。如果j为0则意味着前方没有相匹配的,即是最坏的情况,若不为0,则直接在原有的基础上加一,至于为什么,可以看其他的深入讲解。如果两个都不满足的话,怎么办?那么直接就去看门牌(谐音kmp)即j直接变成以j为下标的next数组的值,最后不断循环,next数组就求出来了;

接下来看nextval

void getnextval(string s)
{
	int i=1;
	nextval[0]=0;
	while(i<s.length())
	{
		int index=nexts[i];
		if(s[i]==s[index])
			nextval[i]=nextval[index];
		else
			nextval[i]=nexts[i];
		i++;
	}
}

nextval的原理即是如果在i位置的字符s[i]如果等于以next【i】的值为下标处的字符串中的字符的话,那么nextval【i】的值就是nextval【next【i】】的值,否则是自身的next【i】的值。

最后看总体kmp

bool kmp(string s1,string s2)
{
	int i=0,j=0;
	getnext(s2);getnextval(s2);
	while(i<s1.length()&&j<s2.length())
	{
		if(j==0||s1[i]==s2[j])
		{
			i++;j++;
		}
		else
		{
			j=nextval[j];
		}
	}
	if(j>=s2.length())
		return true;
	else
		return false;

}

i和j分别源串和字串的下标,如果两个字符相匹配,则继续往下匹配,否则将子串的下标回溯到nextval的值,这就是我们求nextval的意义,用来回溯,避免重复计算。最后如果字串顺利循环完,那么说明匹配成功了,要么那就是失败了。自此,kmp算法就结束了,是不是还不算复杂啊,当然这只是将结论以代码的形式呈现出来,想要深刻了解,可以去看看视频。最后希望大家多给我这个ruog点赞-——来自大一cg的乞讨

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值