KMP

http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

https://www.acwing.com/solution/content/23907/

先上两个大佬的博客

能懂基本的思想了

KMP_第1张图片

 

 

 KMP_第2张图片

 

 

 第二个图来自acw的第二个题解

KMP_第3张图片

 

 

 

KMP_第4张图片

 

 

 看到这里应该就能明白了

OK了,了解到这里就能去听y总的课了...

KMP_第5张图片

 

 

 next[i]表示以i为终点的后缀与和从1开始的前缀相等且这个后缀的长度最长,其实也就是之前博客里又说的匹配表

把子串单独拎出来看

KMP_第6张图片

 

 

 KMP_第7张图片

 

 

 KMP_第8张图片

 

 

 然后移动之后就又开始看看下一个点是否匹配了

好了,现在过程都懂了,开始写代码:

主要分为两个部分:

第一个部分:字符串的匹配

KMP_第9张图片

 

 

 这个是acw下面的一个评论,本来刚开始还不是很理解,现在很理解了

//KMP的匹配过程
for(int i=1;j=0;i<=m;i++)
{
    while(j&&s[i]!=p[j+1]) j=ne[j];//这是一个往后退的过程,找到一个类似于前缀的另一个与s串匹配的位置 
    if(s[i]==p[j+1]) j++;//如果退无可退之后还不满足条件,那就到i的下一个位置
    if(j==n)
    {
        //完成匹配 
    }
}

NND,终于懂了.....

刷了三天,知道是个啥意思了,hhh

#include
using namespace std;
const int N=100010,M=1000010;
char q[N],s[M];
int ne[N];//保存next数组
int main()
{
    int n,m;
    cin>>n>>q+1>>m>>s+1;//下标均从1开始
    for(int i=2,j=0;i<=n;i++)
    //j表示匹配成功的长度,i表示q数组中的下标,因为q数组的下标是从1开始的,只有1个时,一定为0,所以i从2开始
    {
        while(j&&q[i]!=q[j+1]) j=ne[j];
        //如果不行可以换到next数组
        if(q[i]==q[j+1]) j++;
        //成功了就加1
        ne[i]=j;
        //对应其下标
    }
    //j表示匹配成功的长度,因为刚开始还未开始匹配,所以长度为0
    for(int i=1,j=0;i<=m;i++)
    {
        while(j&&s[i]!=q[j+1]) j=ne[j];
        //如果匹配不成功,则换到j对应的next数组中的值
        if(s[i]==q[j+1]) j++;//到退无可退的时候,就进行下一个i 
        //匹配成功了,那么j就加1,继续后面的匹配
        if(j==n)//如果长度等于n了,说明已经完全匹配上去了
        {
            printf("%d ",i-j);
            //因为题目中的下标从0开始,所以i-j不用+1;
            j=ne[j];
            //为了观察其后续是否还能跟S数组后面的数配对成功
        }
    }

    return 0;
}

代码还有点小细节懂的不是很彻底,再刷刷吧...

你可能感兴趣的:(KMP)