KMP匹配算法

KMP算法学习笔记

声明:下文都以S串为原串,T串为模式串,字符串都以0起始

首先介绍暴力算法(BF)

暴力不难想,两个指针i,j,分别表示在S,T中匹配到了哪一位,当j匹配到T末尾时,表示查找成功,否则,j就回退到0

时间复杂度为O(nm)

KMP算法

在介绍KMP算法之前,要引入一个函数:前缀函数

前缀函数(此处为nxt)

定义:最长的相等的真前缀与真后缀的长度

因为我们在匹配i,j的时候失败,那么j本应该回退到0,但是此时我们发现T[0...j-1]与S串的[i-j-2,i-1]是匹配的,那么我们此时应该考虑已经匹配的这一部分能否为下一次匹配贡献

考虑如下情况:

0 1 2 3 4 5 6 7
S: a b a b a b b a b
T: a b a b b
不难发现,当i=3,j=3时,下一位不匹配了,我们此时j应该回退到哪里呢?不难发现j回退到2(nxt[j])是最优的,因为已经匹配的这一部分(abab)和T串的开头(abab)是一样的,(其实就是匹配到j时,T串相同的前后缀)
那么通过解释我们应该可以看出 nxt[j]应该是所有的k满足k<j且T[0...k]=T[j-k...j]的最大值

前缀函数的求解方法:

具体讲解在代码里面

void get_nxt(string T){
	int k=-1;//前缀匹配到了哪里 
	int j=0;//后缀匹配到了哪里 
	nxt[0]=-1;
	int len=T.size();
	while(j<len){
		if(k==-1||T[k]==T[j]){//刚开始或该位匹配 
			if(T[++k]==T[++j])//如果下一位匹配, 
				nxt[j]=nxt[k];//可以类比并查集的路径压缩 
			else
				nxt[j]=k;//不匹配那么就回退到k 
		}
		else 
			k=nxt[k];//该位不匹配就回退前缀指针 
	}
}

KMP算法的流程

现在我们已经求出了前缀函数,那么匹配过程就十分显然了:
维护两个指针i,j,表示在S,T串中匹配到了哪里,如果不匹配,那么j回退到nxt[j]
据此不难有以下代码

int kmp(string S,string T){
	int lens=S.size(),lent=T.size();
	get_nxt(T);
	int i=0,j=0;
	while(i<lens){
		if(j==-1||S[i]==T[j])
			++i,++j;
		else
			j=nxt[j];
		if(j==lent-1)//匹配成功 
			//进行操作 
		
	}
}

例题 剪花布条

求S串中有多少个T串

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
string S,T;
int nxt[N];
void get_nxt(string T){
	int k=-1;
	int j=0;
	nxt[0]=-1;
	int len=T.size();
	while(j<len){
		if(k==-1||T[k]==T[j]){
			if(T[++k]==T[++j]) nxt[j]=nxt[k];
			else nxt[j]=k;
		}
		else k=nxt[k];
	}
}
int kmp(string S,string T){
	int lens=S.size(),lent=T.size();
	get_nxt(T);
	int i=0,j=0,cnt=0;
	while(i<lens){
		if(j==-1||S[i]==T[j]) ++i,++j;
		else j=nxt[j];
		
		if(j==lent)
			cnt++,j=0;
	}
	return cnt;
}

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	string a,b;
	cin>>a;
	while(a!="#"){
		cin>>b;
		cout<<kmp(a,b)<<'\n';
		cin>>a;
	}
	return 0;
}
posted @   爱艺诗篇  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示