kmp算法

介绍

  • KMP 是一个解决模式串在文本串是否出现过,如果出现过,最早出现的位置的经典算法,其实现过程非常精妙
  • Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP 算法”,常用于在一个文本串 S 内查找一个模式串 P 的出现位置,这个算法由Donald Knuth、Vaughan Pratt、James H. Morris 三人于 1977 年联合发表,故取这 3 人的姓氏命名此算法。
  • KMP 方法算法就利用之前判断过的信息,通过一个 next 数组,保存模式串中前后最长公共子序列的长度,每次回溯时,通过 next 数组找到,前面匹配过的位置,省去了大量的计算时间。时间复杂度为O(n+m)

当你学会这个算法你会觉得是如此的unbelievable!!!

实现

KMP算法的主要思想是利用模式串本身的重复信息,构造一个next表:第i位标识从第1个到第i个字符的最长公共前后缀,在匹配失败时,通这个表确定下一次匹配的位置。我们已经知道,前后某部分字串相同,所以当模式串第i位字符串匹配不上时,我们取第i-1位的最长公共前后缀的长度,将前缀移到当前位置,大大缩短了查找时间。

如何去求next呢?

就相当于模式串自己和自己匹配
当前一位匹配成功,就在前面的基础上长度加一,即next[i-1]加1,
如果不是,就回溯,找上一位最长公共前后缀的下一位
图示

KMP代码:

string S,P;//字符串使用前要在前面加一个“ ”例如:P=" "+P;
int Next[N];
void getnext(string P){
	int i,j;
	for(Next[1]=j=0,i=2;P[i];i++){
		while(j&&P[i]!=P[j+1]) j=Next[j];
		if(P[i]==P[j+1]) j++;
		Next[i]=j;
	}
} 
void KMP(string S,string P){
	int i,j;
	for(int j=0,i=1;S[i];i++){
		while(j&&S[i]!=P[j+1]) j=Next[j];
		if(S[i]==P[j+1]) j++;
		if(!P[j+1]){
			//code......
			j=Next[i];//重复的匹配 
			//j=0;//不重复匹配 
		}
	}
} 

例题

例题一
AC代码:照抄模板

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

const int N=1e7+5;
string S,P;
int Next[N];
void getnext(string P){
	int i,j;
	for(Next[1]=j=0,i=2;P[i];i++){
		while(j&&P[i]!=P[j+1]) j=Next[j];
		if(P[i]==P[j+1]) j++;
		Next[i]=j;
	}
} 
void KMP(string S,string P){
	int i,j;
	for(int j=0,i=1;S[i];i++){
		while(j&&S[i]!=P[j+1]) j=Next[j];
		if(S[i]==P[j+1]) j++;
		if(!P[j+1]){
			cout<<i-j+1<<endl;
			j=Next[j];
		}
	}
} 

int main(){
	cin>>S>>P;
	S=" "+S;
	P=" "+P;
	getnext(P);
	KMP(S,P); 
	for(int i=1;i<=P.size()-1;i++){
		cout<<Next[i]<<" ";
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值