2.3KMP算法
写在前面
喜报:听了四遍都没学懂的KMP算法,终于在 gyy 大佬的耐心讲解下搞懂了,大佬orz!!!
因为有ybt,所以直接在上面写吧
正文
kmp算法本质上就是对模式串(要匹配的子串 两个串中短的那个 )中很多重复的前缀和后缀索引起来,使得在一个地方失配了也不要紧,不用重新来的算法(看不懂不要紧)
下面我们就来详细介绍一下kmp的几个操作
预处理
a | b | a | b | c |
---|
用
例如
a | b | a | b | c |
---|
在
在
而在 在
你会发现一个问题,其实 (那干嘛不叫 last 呢)
那聪明的你一定会问:这个是用来干嘛的呢?
别急,让我们来看适配操作
适配
a | b | a | b | e | ... |
---|---|---|---|---|---|
a | b | a | b | c |
我们用
我们先一项一项的配,当配到
别担心,你会发现
所以我就将
提示
其实预处理
复杂度
你考虑j是不是每次都往前跳一格或往后退,它最多前进n次,而后退却是在前进的基础上后退回去的,次数必然小于前进的次数,所以最多给kmp带来
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
char a[N],b[N];
int nxt[N];
int main(){
cin>>a+1>>b+1;
int la=strlen(a+1),lb=strlen(b+1);
for(int i=1,j=0;i<=lb;i++){
while(j&&b[i+1]!=b[j+1]) j=nxt[j]; //如果i+1失配则找到i的上一个相同配子
if(b[i+1]==b[j+1]) j++;
nxt[i+1]=j;//本应该是j+1与i+1匹配但是上面已经j++了
}
for(int i=0,j=0;i<=la;i++){
while(j&&a[i+1]!=b[j+1]) j=nxt[j];
if(a[i+1]==b[j+1]) j++;
if(j==lb){
printf("%d\n",i-lb+2);
}
}
for(int i=1;i<=lb;i++){
printf("%d ",nxt[i]);
}
}
T1:
板子
T2:
因为
T3:
一就是考虑我们要让Q最大就要让绿色框内的字符最短,就是求出来最短的前缀和后缀相等,所以可以考虑二操作,递归nxt直到找到最小的 禁止套娃
T4:
枚举每一个左端点跑一边kmp,然后递归到
还有一个细节,就是为什么j可以直接递归到合法情况而不是再开一个jj去统计,因为考虑在下一层递归时,i的长度只加一,j也是同理,而且也只有满足
我把这篇代码贴出来方便理解
#include<bits/stdc++.h>
using namespace std;
const int N=2e4;
char s[N];
string a;
int k,n,ans;
int nxt[N];
void kmp(){
int len=a.length()-1;
for(int i=1;i<=n;i++){
nxt[i]=0;
}
for(int i=1,j=0;i<=len;i++){
while(j&&a[i+1]!=a[j+1]) j=nxt[j];
if(a[i+1]==a[j+1]) j++;
nxt[i+1]=j;
}
for(int i=1,j=0;i<=len;i++){
while(j&&a[i+1]!=a[j+1]) j=nxt[j];//因为此时j对应的是i+1
if(a[i+1]==a[j+1]) j++;
// int jj=j;
// while(jj*2>=i+1) jj=nxt[jj];//因为此时j对应的是i+1
// if(jj>=k) ans++;
if(j*2>=i+1) j=nxt[j];
if(j>=k) ans++;
}
}
int main(){
scanf("%s%d",s+1,&k);
n=strlen(s+1);
for(int i=1;i<=n;i++){
a.clear();
a+=' ';
a+=s+i;
kmp();
}
printf("%d",ans);
}
T5:
枚举一个串的左端点,用它的后缀与其余的串进行匹配,j最大就是最长字串
T6:
kmp自己做出来的题,好耶!
跑一边kmp,j合法后递归jj,直到
T7:
很容易想到
考虑
如果
T8:
像这种把匹配字符转化到匹配别的东西的方法很经典,就是预处理每个相同字符的位置,但是会有个问题,就是上一个字符可能不在匹配范围内,所以就将这种改成0就行了
我之前将没出现过的设为0
T9:
和T8一样的思路,我们把其转化为几层限制,设
我的思路(假):
我设
90pts,然后唐老师造了一组hack:
3 1 5 4
3 1 5 2
原因:是因为这种只能小范围的相等,只要排列一复杂,限制多了,就会有问题
正解:可以用set+桶来找到离他最近的两个值
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探