next数组的求解
求解思路
根据前j个已经求得到next值来求next[i+1]。
1.设next[i]的值为k(k为最长前后缀匹配的长度),那么next[i+1]最大为k+1。
反证:假设next[i+1]的值大于k+1,那么一定存在next[i]=k+1,与假设next[i]=k矛盾。
2.如果当前最长前缀寻找失败,那么下一个最长匹配子串只可能出现在前k个元素中,且长度等于next[j]
也可以用反证法求解
3.其他的原理见KMP分析
求解方法
设i为当前所求next的下标,j为当前待验证的最长匹配前缀长度(也是和当前求解子串的最后一个元素进行比较的元素)
1.next[0]=-1,作为每次探寻next的结束标志
2.若成功匹配到前缀或者已经探寻结束了,那么令next[i]=j+1;
3.否则,让j=next[j],即让j等于当前长度前缀的最长前缀子串
KMP
1.结束标志:(1)当匹配成功,即遍历完待匹配的串时,即j==sizeof(匹配串)(2)当i==sizeof(主串)且j!=sizeof(匹配串)
代码如下:
#include<string>
#include<iostream>
#include<vector>
using namespace std;
void getnext(string &s,vector<int> &next){
next[0]=-1;
int i=1,j=-1;
while(i<next.size()){
if(j==-1||s[i-1]==s[j])
next[i++]=++j;
else
j=next[j];
}
}
int kmp(string &s,string &p){
vector<int> next(p.size());
getnext(p,next);
cout<<"next数组为:"<<endl;
for(int i=0;i<next.size();i++){
cout<<next[i]<<' ';
}
cout<<endl;
for(int i=0,j=0;i<s.size();){
if(s[i]!=p[j]){
if(j==0) i++;
else j=next[j];
}
else{
i++;j++;
}
if(j==p.size())
return i-j;
}
return -1;
}
int main(){
string s="abcabaaaabaabcac";
string p="abaa";
cout<<"kmp匹配结果为:"<<kmp(s,p)<<endl;
}