KMP模板(看了一个下午加一个晚上)
大家不要嫌我讲故事,我就亿点点自闭
KMP算法大家应该都知道是用来处理字符串快速查找的问题,通常会跟前缀后缀结合,时间复杂度很神奇O(m+n)!其中n、m分别为字符串长度。算法核心应该就是match数组(有些称next数组),以及匹配过程。对于原理,推荐去MOOC上看越姥姥数据结构的的KMP讲解,真的好懂,不过我感觉有些缺陷,个人感觉,对于做题不是很友好,(可能我太菜),一下展示我学到的姥姥的代码
//具体可以看姥姥的慕课,真的好懂
const int maxn=1e5+5;
int match[maxn];
void get_match(string s2){
match[0]=-1;
for(int j=1;j<s2.length();j++){
int temp=match[j-1];
while(temp>=0&&(s2[temp+1]!=s2[j])){
temp=match[temp];
}
if(s2[temp+1]==s2[j]){
match[j]=temp+1;
}
else match[j]=-1;
}
}
int KMP(string s1,string s2){ //从s1里找s2
if(s1.length()<s2.length()) return -1;
get_match(s2);
int s=0,p=0;
while(s<s1.length()&&p<s2.length()){
if(s1[s]==s2[p]) s++,p++;
else if(p>0) p=match[p-1]+1;
else s++;
}
if(p==s2.length()) return s-p; //返回找到字串的下标
else return -1; //没找到
}
学完后觉得不太难,我很高兴做完了姥姥的例题,觉得我学会了。直到最近要学AC自动机看了篇博客,说前提要学会KMP和tire树,于是重新看起KMP,使用了姥姥的模板,去洛谷,POJ上找了两题模板,发现了问题。而且几乎所有博客上的match数组都和姥姥的不太一样。可是我先入为主了,把姥姥的模板调试了一个下午都还是过不了,于是我去b站上看了灯神的KMP讲法,也是稀里糊涂了半天,下面贴下b站链接:这个吹爆
看了大概对match数组有了一定了解,但会发现和姥姥上的不太一样。。。
于是疯狂找博客,感觉在摸鱼
题目传送门:添加链接描述
下午自己编的数据,以下都以这个为样例 S1=AAABAAABAA,S2=AAABAA
const int maxn=1e6+5;
int match[maxn];
char s1[maxn],s2[maxn];
int ans;
void get_match(char *s2){//一定要自己手动模拟,会发现很神奇
int k=-1,j=0;//j表示当前位置
match[0]=-1;
int len=strlen(s2);
while(j<len){
if(k==-1||s2[k]==s2[j]){ //具体可以看我写的,真的神奇
k++;
j++;
match[j]=k;
}
else{
k=match[k];
}
}
}
int KMP(char* s1,char* s2){
get_match(s2);
int s=0,p=0;
int len=strlen(s1),len2=strlen(s2);
while(s<len){
if(p==-1||s1[s]==s2[p]){
s++;
p++;
}
else p=match[p];
if(p==len2){
cout<<s-len2+1<<'\n'; //找到位置返回s-len2+1,若计数则ans++,p=match[p];
p=match[p];
}
}
return ans;
}
这段代码我个人感觉不是很好懂,我整整傻看了一个下午加一个晚上,心烦意乱,其实静下心来自己模拟一遍会发现很神奇,下面是我手写的一些过程,对自己以后也有帮助
有了这个模板就可以做有些模板题了,仅仅是模板,看了HDU上有关KMP的题,觉着还是要对match数组有更深的了解,一下贴一下POJ的代码,就当以后自己的模板了,对于KMP的过程,下次补上。写这博客应该自己看的多,我也就瞎写了
//格式好丑,题目链接在上面
#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<list>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int match[maxn];
char s1[maxn],s2[maxn];
int ans;
void get_match(char *s2){
int k=-1,j=0;
match[0]=-1;
int len=strlen(s2);
while(j<len){
if(k==-1||s2[k]==s2[j]){
k++;
j++;
match[j]=k;
}
else{
k=match[k];
}
}
}
int KMP(char* s1,char* s2){
get_match(s2);
int s=0,p=0;
int len=strlen(s1),len2=strlen(s2);
while(s<len){
if(p==-1||s1[s]==s2[p]){
s++;
p++;
}
else p=match[p];
if(p==len2){
cout<<s-len2+1<<'\n';
p=match[p];
}
}
return ans;
}
int main()
{
scanf("%s%s",s1,s2);
KMP(s1,s2);
for(int i=1;i<=strlen(s2);i++){
cout<<match[i]<<' ';
}
return 0;
}
/*AAABAA
AAABAAABAAA*/
还是太菜了傻看了那么久,还是好多题不会,别人应该看半小时就会了吧。以后还有好多东西要学