kmp算法是用来找A字符串的子串B的出现次数和位置的一种算法;
在看后面之前先看一个链接https://kb.cnblogs.com/page/176818/
然后对算法就有个大概的理解
为了实现这种算法我们需要一个next数组,也就是刚才链接里的部分匹配表,next[i]表示‘B中以i结尾的非前缀子串’与’B的前缀‘能够匹配的最长长度;
如:abababaac的i=7 为结尾的’非前缀子串‘有6个,分别是2~7,3~7,4~7,....,7~7;
如B【2~7】=’bababa‘与前缀’ababab‘不匹配
B【 3~7】=‘ababa’与前缀‘ababa‘匹配,长度为5;
.............
得出next【7】=5;
但如何求出next数组我们可以假设next【1~6】已经被求出。next【6】=4;及B【3~6】与B【1~4】匹配;
接下来,B【7】=B【5】=’a‘,所以B【7】=5;皆大欢喜,下一个匹配了;
但当next【8】时,B【8】=‘a‘ B【6】=’b‘不匹配;
所以我们只好把匹配长度缩短;就是说上面我们以i=7接韦德匹配长度出了5之外,还有B[5~7]于B【1~3】的长度为3的匹配;B【1】于B【7】的长度为1的匹配;
我们尝试这两种匹配能否使i=8时匹配;
但B【8】于B【4】,B【2】不相等,所以我们只能让i=8冲头开始匹配,B【1】恰好于B【8】匹配;所以next【8】=1;
单我们是如何记路5,3,1这些匹配长度的?
首先next【7】=5;说明从i=7往前5个字符于B【1~5】是相等的。
这是我们定义一个j;使从5往前j个字符与B【1~j】匹配;什么意思,就是以5为next【5】;(别忘了next数组定义);
当j=next【5】=3之后,下一个要找的就是next【3】;
所以代码就有了(可能还没有,看看代码就会了)
1.初始化next【1】=j=0,假设next【1~i-1】都求出,正在求next【i】。 2.尝试匹配下一位,若果匹配失败,就令j=next【j】(上面讲了为什么)。直到j=0; 3.若果匹配,就令j+1,next【i】=j; next[1]=0; for(int i=2,j=0;i<=strlen(a);++i) { while(j>0 && a[i]!=a[j+1]) j=next[j]; ////匹配失败 if(a[i]==a[j+1]) j++; /// 匹配成功 next[i]=j; }
然后有了next数组就可以kmp了
for(int i=1,j=0;i<=strlen(b);++i) { while(j>0 && (j==n || b[i]!=a[j+1])) j=next[j]; if(b[i]==a[j+1]) j++; if(j==strlen(a)) ///此时匹配 位置为i-strlen(a)+1 }
然后就没了;