KMP算法小窥

首先对于KMP算法中的KMP做稍微的解释 KMP是三个人完事

KMP算法做了什么

显而易见,就是找子字符串嘛
从ABABABD中找ABD 那么自然而然你会相当暴力双重循环非常快,但是你有没有想过一个问题,你之前循环的东西,能不能帮助你后面找呢?
KMP就是做了一个这么样的东西,理用之前循环的内容 加快寻找速度。

首先介绍前后缀

定义:
前缀是指包含第一个字符的,不包含最后一个字符的,按从头到尾的顺序的字符串。
后缀是指不包含第一个字符串的,包含最后一个字符的,按从头到尾的顺序的字符串。
相同前后缀有:
举例:例子:aabaa
前缀有:a,aa,aab,aaba
后缀有:a,aa,baa,abaa
相同前后缀有:a,aa 最大相同前后缀有aa
说到这里你就应该有了大致的想法,相同的前后缀,就是我们要理用的信息。

相同前后缀的作用

例子:串A:aabaabaaf 串B:aabaaf
首先 我会因为匹配aabaab和aabaaf中bf不相同嘛,此时
aabaa在AB都出现了,
在串A中的aabaa 和串B 中的aabaa(注意黑色部分)是相同的,那是不是说明,我下次直接从串A的aabaa后面的去比较aabaa就可以了
也就是
串Aaabaab
串B aab
就可以了
那为什么我知道从哪里开始接着比较就可以了呢?
因为我知道相同前后缀啊
既然在AB能匹配到aabaa 不就说明了A,B中都包含包含aabaa嘛 那A中的后缀是可以匹配B中的前缀的啊,不就说明我可以利用这一点加速吗?

我如何求相同前后缀呢?

同样很自然而然可以想到:从前往后。从前往后双指针遍历即可
可是那还是没有用上KMP的思想,上一次遍历的,要提供给下一次遍历使用
这里我直接上代码段讲:

    void getNext(int* next, const string& s) {
        int j = 0;
        for(int i=1;i<s.size();i++){
            while(j>0&&s[i]!=s[j]) j=next[j-1];
            if(s[i]==s[j]) j++;
            next[i]=j;
        }
    }

然后用一个别人的图(代码随想录)(我写的是图片中的next+1的算法,但是核心内容没有区别 他的起点是-1.我的起点是0)
在这里插入图片描述

        while(j>0&&s[i]!=s[j]) j=next[j-1];
        if(s[i]==s[j]) j++;

这两个就是最关键的代码(想了好久都表达不出来,算了反正自己看不用大白话了)
对于if语句,如果有aa=aa 然后i指向的和j指向的又相等,说明一定有aa_=aa_所以相同前后可以加一个

对于while为什么是j=next[j-1]
举例aabaaccaabaab aabaaccaabaaf匹配失败,然后就要j回退,回退的理由是
aabaa①ccaabaa② b
aabaa③ccaabaa④f 有①等于③ ②等于④ 然后之前求
aabaa①ccaabaa② 是知道①和②相同所以四个都相同,所以直接回退到①的后面去匹配aabaab和aabaaf中的bf

done

至此 关键部分已经求完,剩下的就是理用next数组了,留给读者自己解决,当作是作业,可以帮助你理解next到底是什么~~(如果有读者的话)~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值