KMP与周期字符串前缀

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(nm)) 但对于随机数据,朴素算法也是相当快的。
而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还要对自匹配优化,但复杂度不变,加了后错误加一大堆,实际上我觉得没什么用
大概就是这个样子,如果有什么问题,或错误,请在评论区提出,谢谢。

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/u011327397/article/details/52137860
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞