题解:P3375 【模板】KMP (显眼包)
Update on 2025/7/28:将讨论区里提出的常见问题做出解答,应用新版格式,并删除开头废话。麻烦管理员通过。
如有问题欢迎在讨论区提出!
用途
在字符串初级算法里,而其中最经典的模型问题就是判断一个串是否是另一个串的子串。我们常用 KMP 算法解决这类问题。
题目描述
给定两个字符串
在本题解中,我用
暴力匹配
枚举
判断两个串匹配成功的条件是:两个串长度一致,两个串每一个对应位置字符都完全一样。
本做法时间复杂度为 比总司令高。
更优做法:KMP
定义
定义一个字符串性质——前缀后缀最大值,即题目中要求的 border(让你求那多半要用)。
定义一个字符串
s 的 border 为s 的一个非s 本身的子串t ,满足t 既是s 的前缀,又是s 的后缀。
我将字符串 别问我为啥。
换句话说,kmp[i] 就是
匹配过程
举例说明,其中 ABACABACABD,ABACABD。
先将
i
ABACABACABD
ABACABD
j
仔细回想
i
ABACABACABD
ABACABD
j
这样做,复杂度为
求 next
将
具体实现见代码。
实现
::::info[代码]
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+2;
int kmp[N],la,lb,j;
//kmp即Next数组,表示相同前缀后缀最大值(不是对称的最大值)
string a,b,A,B;
int main(){
cin>>A>>B;
a='\0'+A,b='\0'+B;
la=a.size()-1,lb=b.size()-1;
for(int i=2;i<=lb;i++){//求kmp
while(j&&b[i]!=b[j+1]) j=kmp[j];
if(b[j+1]==b[i]) j++;
kmp[i]=j;
}
j=0;
for(int i=1;i<=la;i++){//匹配
while(j>0&&b[j+1]!=a[i]) j=kmp[j];
if(b[j+1]==a[i]) j++;
if(j==lb){printf("%d\n",i-lb+1);j=kmp[j];}
}
for(int i=1;i<=lb;i++) printf("%d ",kmp[i]);
return 0;
}
::::
::::warning[讨论区常见问题]
问题
为什么求 kmp 数组(代码第 12 行)下标 b.size()-1 结束啊?
回答
首先 b.size()-1 结束并不难理解,我加了个空字符 \0 来让字符串下标从 b.size() 求出的大小会把 \0 算上,因此要减一。
然后回答为什么 kmp 数组的定义和作用,然后再手动推一下发现如果从 kmp[1] 就会变为
::::
点个赞再走呗。