浅谈KMP

浅谈KMP

简介

KMP是由三位大神联合发表的

分别是

D.E.Knuth
J.H.Morris
V.R.Pratt

取其首字母,叫KMP算法

这个算法作用是解决字符串匹配问题

时间接近复杂度O(n+m)

暴力解决

算法思路:

从每一位开头,向后匹配

如果匹配完了返回找到

如果每一位都试过了就没找到

O(n*m)

#include<bits/stdc++.h>
using namespace std;
string a,b;
int n,m;
int main( ){
	cin>>a>>b;
	n=a.size( );m=b.size( );
	int i,j;
	for(i=0;i<n;i++){
		j=0;
		while(j<m&&a[i+j]==b[j])j++;
		if(j==m)goto OK;
	}
	goto GG;
	OK:
		puts("Yes");
		return 0;
	GG:
		puts("No");
		return 0;
}

暴力算法不足处

对于字符串aaaaaaaaaaabaaaaab

我们发现每次匹配完

都是从下一位开始

KMP算法思路

但我们人为匹配是怎么样的?

对于aaacaac

我们发现aac无法与aaa匹配

那么就将aac第3位与aaac第的第4位匹配

就找到了

KMP算法实现

我们发现如果

abaaabc
abaaaba

的在c位无法匹配

下次不是将aaaaac从第二位重新比较

而是将倒数第3位的a与最后一位a重新比较

为什么呢?

我们发现倒数第二位之前的字符串后缀和前缀最大就是ab

于是发现有重复的部分

也就是说可以跳过ab和中间的进行匹配

KMP算法核心之一,next数组

那我们的任务就是求出next数组(即最长相等前缀后缀)

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

详细有很多人看不懂k=next[k]

这里有点绕,但是并不难

因为对于字符串

AAABAAAA
  |    |

我们发现BA不匹配

呢么就要回退

回退到哪里呢?next[k]指针所指的地方

再次与当前位置比较

KMP算法

理解了前面那个,就是对思路的实现了

#include<bits/stdc++.h>
using namespace std;
void work( ){
	int next[10000];
	string a,b;
	int j=0,k=-1,i,n,m;
	cin>>a;
	if(a=="#")exit(0);
	cin>>b;
	n=a.size( );
	m=b.size( );
	next[0]=-1;
	next[1]=0;
	while(j<m){
		if(k==-1||b[j]==b[k]){
			++j;++k;
			next[j]=k;
		}else k=next[k];
	}
	int ans=0;
	i=0;j=0;
	while(i<n){
		if(j==-1||a[i]==b[j]){
			if(j==m-1)goto OK;
			++i;
			++j;
		}else j=next[j];
	}
	goto GG;
	OK:
		puts("Yes");
		return;
	GG:
		puts("No");
		return;
}
int main( ){
	while(1)work( );
}

例题

剪花布条

简单的KMP应用

#include<bits/stdc++.h>
using namespace std;
void work( ){
	int next[10000];
	string a,b;
	int j=0,k=-1,i,n,m;
	cin>>a;
	if(a=="#")exit(0);
	cin>>b;
	n=a.size( );
	m=b.size( );
	next[0]=-1;
	next[1]=0;
	while(j<m){
		if(k==-1||b[j]==b[k]){
			++j;++k;
			next[j]=k;
		}else k=next[k];
	}
	int ans=0;
	i=0;j=0;
	while(i<n){
		if(j==-1||a[i]==b[j]){
			if(j==m-1)ans++;
			++i;
			++j;
		}else j=next[j];
	}
	cout<<ans<<endl;
}
int main( ){
	work( );
}
posted @ 2020-04-11 13:28  Mikasa_Ackerman  阅读(174)  评论(0编辑  收藏  举报