kmp自然就是字符串匹配,基本信息什么的我就不说了,反正时间复杂度是 O(m+n) n是待检测的字符串长度,m是模板链的长度,速度很快,代码也很简单,但是理解起来特别是对于没接触过的很有困难 。
我这里就简要叙述一下kmp的核心过程,想看图百度一下全都是图,我也就不想画了,也不盗别人的图的,我就自己直接来说一下。
首先字符串匹配最简单的就是朴素算法
for(int i=0;i<len_n;i++)
{
int j;
for(j=0;j<len_m;j++)
if(n[i+j]!=m[j])break;
if(j==len_m)printf("%d ",i);
}
直接遍历每一个n上每一个点,然后向后直接搜索,验证这个点是否是匹配点,最坏时间复杂度 O(m(n−m)) 但对于随机数据,朴素算法也是相当快的。
而kmp的核心思想就是不重复遍历一个点,假如我们向后搜索的时候遍历过一个点,我们能不能不再次遍历这个店,这就是kmp的核心思想,要实现这个核心思想也很简单,就是不遍历每一个n上每一个点,而是跳着向前走,跳过搜索过的点,这时我们只需要再加一个next数组,告诉我们跳过了这一段之后模板链该从哪里向后搜
那么现在最重要的事情就是找next数组,怎么找?
自己匹配自己
现象前找到最前面的已匹配上的点,再向后找可不可以继续匹配
代码如下:
for(int i=1;i<=n;i++)
{
int j=next[i];
while(j&&m[j]!=m[i])j=next[j];
next[i+1]=m[j]==m[i]?j+1:0;
}
找到了next数组就很简单了,我这里不再多说
for(int i=0;i<len_n;i++)
{
while(j&&m[j]!=n[i])j=next[j];
if(m[j]==n[i])j++;
if(j==m)
{
printf("%d ",i-m+1);
j=0;
}
}
然后这里说一下找周期前缀,如aabaabaabaab,当前缀长度为2,6,9,12时,前缀为周期字符串,可以直接用找next数组的办法找,先自匹配,找到错位部分,如果剩余部分的长度是错位部分的整数倍,那么就是一个周期字符串。
找到next数组后加上这个就可以了。
for(int i=1;i<=len_n;i++)
if(next[i]&&(i%(i-next[i])==0))
printf("%d %d\n",i,i/(i-next[i]));
然后最后说一句,这个只是MP算法,kmp还要对自匹配优化,但复杂度不变,加了后错误加一大堆,实际上我觉得没什么用
大概就是这个样子,如果有什么问题,或错误,请在评论区提出,谢谢。