KMP 字符串匹配 学习笔记

前言

最近才发现自己写了后缀数组,但并没有其他的字符串算法,今天先把 KMP 字符串匹配先讲一下。

算法核心

对于字符串匹配,最朴素的方法就是一个字符一个字符地匹配,找到不同的就直接换一个地方匹配。

我们先来看一组样例:
ababababe

ababe

对于这组样例,暴力的方法就是直接匹配,从第一位开始匹配,发现从第五个地方开始不一样了,那么我们就直接往后移:
ababababe

ababe

发现从第五位开始不一样了,继续往后面移:

ababababe

ababe

以此类推,我们在第五位发现成功匹配了。

不过这样匹配速度太慢了,复杂度为 O(nm),然后我们自己直接想肯定不会一个一个的慢慢想,我们在匹配第一个匹配失败后会将模式串(也就是小的那一个)第三第四位直接移到第一第二位(因为他们相同)。那么就可以知道 KMP 的核心其实就在,每次匹配失败后,将模式串移到相同的地方。

然后就可以想到预处理出一个数组 ppj 表示在匹配到第 j 个字母而 j+1 个字母不能匹配是,可以移动到前面和当前相同的地方,也就是要 t1t2tpj=tjpj+1tjpj+2tj 的最大值。

然后使得 sij+1sij+2si=t1t2tj 继续进行匹配。

然后就很清晰了。

p 数组

自己匹配自己,然后就可以在匹配失败的时候移动到相同的地方以优化。

代码:
for(int i=1;i<m;++i){
    while(j>0&&t[j+1]!=t[i+1])
		j=p[j];
    if(t[i+1]==t[j+1])
		++j;
	p[i+1]=j;
}

Code

#include<bits/stdc++.h>
#define int long long 
using namespace std;
inline int read(){
	int x=0,f=1;
	char ch;
	ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-f;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+(ch-'0');
		ch=getchar();
	}
	return x*f;
}
char s[10000000],t[10000000];
int n,m,p[11000000];
signed main(){
    scanf("%s%s",s+1,t+1);
    p[1]=0;
    n=strlen(s+1),m=strlen(t+1);
    int j=0;
    for(int i=1;i<m;++i){
        while(j>0&&t[j+1]!=t[i+1])
			j=p[j];
        if(t[i+1]==t[j+1])
			++j;
		p[i+1]=j;
    }
    j=0;
    for(int i=0;i<n;++i){
        while
			j=p[j];
        if(t[j+1]==s[i+1])
			++j;
        if(j==m){
			cout<<i-m+2<<endl;
			j=p[j];
		}
    }
    for(int i=1;i<=m;++i)printf("%d ",p[i]);
    return 0;
}

时间复杂度为:O(n+m)(不会重复匹配)。

posted @   bhbjzyh  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示