KMP算法Next数组详解

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

KMP算法Next数组详解
题⾯
题⽬描述
如题,给出两个字符串s1和s2,其中s2为s1的⼦串,求出s2在s1中所有出现的位置。

为了减少骗分的情况,接下来还要输出⼦串的前缀数组next。

如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习⼀下就知道了。

输⼊输出格式
输⼊格式:
第⼀⾏为⼀个字符串,即为s1(仅包含⼤写字母)
第⼆⾏为⼀个字符串,即为s2(仅包含⼤写字母)
输出格式:
若⼲⾏,每⾏包含⼀个整数,表⽰s2在s1中出现的位置
接下来1⾏,包括length(s2)个整数,表⽰前缀数组next[i]的值。

输⼊样例:
ABABABC
ABA
输出样例:
1
3
0 0 1
说明
时空限制:1000ms,128M
数据规模:
设s1长度为N,s2长度为M
对于30%的数据:N<=15,M<=5
对于70%的数据:N<=10000,M<=100
对于100%的数据:N<=1000000,M<=1000
题解
这是⼀道KMP裸题(模板题。


我就是拿着它学习⼀下KMP算法
其实原来我学过KMP算法
但是⼀直没有弄懂next(跳转)数组是如何求出来的。

最近花了⼀个下午⾃⼰研究了⼀下KMP算法
现在终于觉得KMP很简单了~
现在直接说next数组把
⾄于有什么作⽤,next数组是⼲什么的,请⾃⾏百度,有很多dalao总结的⾮常到位,看⼀看就会明⽩。

好,来说next数组
并不⽤在意这⼀坨⿊的是什么东西,我们就假设他是我们要求next数组的字符串。

next数组求的东西就是从起始位置到当前位置最长的相等的前缀和后缀的长度。

(举个例⼦China的前缀有:C、Ch、Chi、Chin、China ;后缀有a、na、ina、hina、China)
我们继续,如上图红⾊的是当前位置(设为j)前,所匹配上的最长前缀和后缀,蓝⾊的是当前要匹配的位置。

那么,我们就拿当前位置和原来匹配到的最长前缀的后⼀位相⽐较
如果两个位置相同,
显然,
可以和前⾯的红⾊连在⼀起,
此时就有next[j]=next[j-1]+1
如果两个位置不相同,
根据next数组的性质,
显然的,你的当前的相等的前缀和后缀只能够继续向前找,
也就是说,你当前的next数组⼀定会减⼩。

既然前⾯的红⾊部分存在⼀⼩块灰⾊,那么,后⾯的红⾊部分也必然存在灰⾊部分。

所以,判断当前位置和前⾯那⼀块灰⾊的前缀的后⼀位是否相等。

如果这两位相同的话,不就可以和前⾯的灰⾊部分连在⼀起了吗
此时,⼜回到⼀开始的那⼀步。

因此,求解某个位置的next值是⼀个循环过程。

不断检查上⼀位的最长前缀的后⼀位(i位置)(这句⼦有点拗⼝)
如果相等next[j]=next[i]+1
否则令 i=next[i-1]+1,继续循环匹配
如果没有看懂就⾃⼰多看⼏遍,⾃⼰找⼏个字符串算⼀算
所以:求解next数组的代码:
inline void GetNext(string s)//获得字符串s的next数组
{
int l=s.length(),t;
Next[0]=-1;//如果在0位置失配则是向下移动⼀位
for(int i=1;i<l;++i)//依次求解后⾯的next数组
{
t=Next[i-1];
while(s[t+1]!=s[i]&&t>=0)//循环求解next值
t=Next[t];
if(s[t+1]==s[i])//如果是匹配上⽽退出循环
Next[i]=t+1;
else //否则则是匹配不上
Next[i]=-1; //指向头
}
}
代码很简洁的~
那么,接下来如何利⽤Next数组求解匹配
那就⾃⼰baidu吧(知道了next数组,KMP就很好理解了)接下来贴上⼩蒟蒻的源码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int MAX=1001;
int Next[MAX];
vector<int> Ans;
inline void GetNext(string s)//获得字符串s的next数组
{
int l=s.length(),t;
Next[0]=-1;//如果在0位置失配则是向下移动⼀位
for(int i=1;i<l;++i)//依次求解后⾯的next数组
{
t=Next[i-1];
while(s[t+1]!=s[i]&&t>=0)//循环求解next值
t=Next[t];
if(s[t+1]==s[i])//如果是匹配上⽽退出循环
Next[i]=t+1;
else //否则则是匹配不上
Next[i]=-1; //指向头
}
}
inline void KMP(string s1,string s2)
{
GetNext(s2);
int l1=s1.length();
int l2=s2.length();
int i=0,j=0;
while(j<l1)
{
if(s2[i]==s1[j])//当前位匹配成功,继续匹配下⼀位
{
++i;++j;
if(i==l2)//完全匹配
{
Ans.push_back(j-l2+1);//储存答案
i=Next[i-1]+1;//继续匹配
}
}
else
{
if(i==0)//在⾸位不匹配
j++;//直接向后挪⼀位
else
i=Next[i-1]+1;//跳转
}
}
}
int main()
{
string s1,s2;
int l;
cin>>s1>>s2;
l=s2.length();
KMP(s1,s2);
for(int i=0;i<Ans.size();++i)
cout<<Ans[i]<<endl;
for(int i=0;i<l;++i)
cout<<Next[i]+1<<' ';
cout<<endl;
return 0;
}
最后再说⼀句
如果需要加深理解KMP的过程请去SYC的blog看看他的gif动图你可能就会有更多了解。

相关文档
最新文档