首先对于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中的b和f
done
至此 关键部分已经求完,剩下的就是理用next数组了,留给读者自己解决,当作是作业,可以帮助你理解next到底是什么~~(如果有读者的话)~~