KMP算法

Posted 归游

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KMP算法相关的知识,希望对你有一定的参考价值。

模板】KMP字符串匹配

KMP字符串匹配用于两个字符串中,是否一个字符串是另一个的子串

我们称其中两个串一个为S(长度为n),一个为P(长度为m),问是否P为S的字串

这种题暴力的想法很容易想到但时间复杂度为\\(O(nm)\\)

其实KMP也就只是在暴力的想法上进行了优化,不过优化的程度很高

举例
S:a b a d a b a
P: a b b

暴力思路就是枚举主串的每个字符,然后从枚举到的字符后m个字符是否有一样即可

而暴力的思路明显存在缺点,一旦匹配失败就只右移一位,然后从头继续匹配

而KMP的思路是移动多位(那么此时同学会想,移动多位会不会丢失一些可能可以匹配的字符串?且接着往下看)

这个疑问非常有道理,所以KMP的算法妙就妙在这里,跳过一些不可能匹配成功的位置

这个问题被很好的解决,通过next数组

next[i]数组存储的是以P[0~i]为字符串的以长度为k的前缀和后缀相等,k取最大(k<=i)(长度不能等于i+1,因为如此自己便等于自己,自己等于自己无意义)
简而言之,最长同前缀后缀

假如匹配到某个位置\\(x(x<m)\\)

\\(S[l~r]=P[0~x]\\)

但是\\(S[r+1]!=P[x+1]\\)

按暴力的算法我们会想去从头开始匹配
例如
\\(S[l+1]==P[0]\\)

但我们发现其实\\(S[l\\) ~ \\(r]=P[0\\) ~ \\(x]\\)这一段是匹配过的

如果存在\\(S[l~r]\\)中某一段\\([l\'\\) ~ \\(r\']\\)等于某一段\\([h\\) ~ \\(t]\\),就可以使$ P[0 $~ \\(r\'-l\']=S[h\\) ~ \\(t]\\)
同时从其他地方开始匹配也绝无可能,这样就能大大降低复杂度

你会发现前面引入的next数组完美解决了上述问题,

最长同长度前后缀满足某段等于某段,而且最长的前后缀,使得其他地方也不存在匹配成功的可能(很好的思考题,这里的原因)

  • 证明(非严谨)
    如果存在 $P[0 $ ~ $ x]=S[r-x+1$ ~\\(r]\\)且不是最长同前缀后缀,那么x一定小于最长同前缀后缀的长度

next数组求法

也有暴力求法,但时间复杂度为\\(O(m^2)\\),违背了我们降低算法复杂度的初心

你想想\\(next[i]\\)\\(next[i-1]\\)有没有联系
如果\\(P[next[i-1]]=P[i]\\),显然\\(next[i]=next[i-1]+1\\)

如果≠,存在\\(P[0~next[i-1]]=p[i-1-next[i-1]~i-1]\\)

所以存在$P[0 $~ \\(next[ next[ i-1 ] ]-1 ]=P[ next [ i-next[ i-1 ]-1\\) ~ \\(i-1]]\\)

这时沿用上述的思路 如果\\(P[next[i-1]]=P[i],\\)也可以\\(next[i]=next[next[i-1]]+1\\)
否则,我们可以继续是否存在\\(next[next[next[..]]]\\)是成立,直到\\(next[next[...]]=0\\)

  • code
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;
const int maxn=1e6+10;
char a[maxn],b[maxn];
int nex[maxn]={0};
int top=0;
int main(){
	ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
	cin>>(a+1)>>(b+1);
	int lena=strlen(a+1),lenb=strlen(b+1);
	for(int i=2,j=0;i<=lenb;++i){
		while(b[i]!=b[j+1] && j) j=nex[j];
		if(b[j+1]==b[i]) ++j;
		nex[i]=j;
	}
	for(int i=1,j=0;i<=lena;++i){
		while(j&& b[j+1]!=a[i]) j=nex[j];
		if(b[j+1]==a[i]) ++j;
		if(j==lenb) {
			cout<<i-lenb+1<<endl;
			j=nex[j];
		}
	}
	for(int i=1;i<=lenb;++i) cout<<nex[i]<<" ";
	return 0;
}

以上是关于KMP算法的主要内容,如果未能解决你的问题,请参考以下文章

数据结构—串KMP模式匹配算法

Python ---- KMP(博文推荐+代码)

KMP算法及Python代码

KMP算法及Python代码

图解KMP算法原理及其代码分析

Kmp算法Java代码实现