【最浅显易懂的 KMP 算法讲解】https://www.bilibili.com/video/BV1AY4y157yL?vd_source=757e0fceb4526f3b51243a4422760ebe
下面代码结合上面视频(有动画展示)食用最宜;
代码根据上面视频整理所得,并加入非常多的注释。
#include <iostream>
using namespace std;
//Next数组第一个默认为零,prefix_len是公共子串长度,kmp_search函数之外,定义的i是主函数里指向子串的指针,j是Next数组的下标。
int Next[111111]={0},prefix_len=0,i=1,j=1;
//主串与子串。
string s,s1;
int kmp_search(string s,string s1){
int i=0,j=0;//i是主串中的指针,j是子串的指针,都是从零开始;
//lens是主串的长度,lens1是子串的长度;
int lens=(int)s.length();
int lens1=(int)s1.length();
//主串的指针i是一直往后移 ,不向前回溯的。
while(i<lens){
//字符匹配,两个指针都往后移。
if(s[i]==s1[j]){
i+=1;
j+=1;
}
//字符匹配失败,根据之前求的Next数组 跳过子串前面的一些字符。
else if(j>0){
j=Next[j-1];
}
//字符匹配不仅失败了,而且一开始就失败了,所以主串的指针向下一个移
else {
i+=1;
}
//最后一个位置lens-1如果相同,j会加一,所以这里判断j是否与lens相等;
if(j==lens1){
return i-j;
}
}
//找不到返回-1;
return -1;
}
int main(){
//首先输入主串与子串。
cin>>s>>s1;
//子串的长度
int len=(int)s1.length();
//使用递推的方法来遍历子串求Next数组,此处最难理解;
while(i<len){
//指针指向0时,没有子串,所以i初始值为1,Next数组第一个初始为零;
//此处可以看做前缀与后缀比较
if(s1[prefix_len]==s1[i]){
prefix_len+=1;
Next[j++]=prefix_len;
i+=1;
}
//如果下一个字符不匹配的话 下面的两种情况
else{
//如果共同的字符串为零,直接赋值Next数组直接赋值为零
if(prefix_len==0){
Next[j++]=0;
i+=1;
}
//不是零的情况,就在相同子串中,查找更小的相同字串
//一直回溯,回溯到找到相同的字串,或者相同的字串长度为0,在上面if语句中结束本次回溯;
else {
prefix_len=Next[prefix_len-1];
}
}
}
cout<<kmp_search(s,s1);
return 0;
}