KMP算法
KMP算法是一种改的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。
问题:给一个目标串T:ABABCDEFG,模式串P:ABC,找出P在T中完全匹配出现的位置
1.简单的字符串模式匹配
遍历每一个T的位置,从该位置往后挨个元素和P中元素对比是否相同,相同则一起往后遍历,不同则移动T的指针i。复杂度O(mn).
int str_match(string t, string p){
int i=0,j=0;
while(i<t.size()&&j<p.size()){
if(t[i]==p[j]){
++i;
++j;
}else{
i=i-j+1;
j=0;
}
}
if(j==p.size()-1)
return i-j;
else
return -1;
}
2.KMP
比如T:ABABCBCD、P:ABABD 匹配,当匹配到第5位时候,T为ABABC,P为ABABD出现不同,其实不必移动到T的第二位从头开始比较(移动i指针),也可以移动j指针,因为P中前面也有AB与T的末位相同。
这个东西不看图很难懂的,目前没时间画图改博客,抢先看以下两个链接,两个兄弟讲得很好
http://www.cnblogs.com/tangzhengyue/p/4315393.html
https://www.cnblogs.com/yjiyjige/p/3263858.html
vector<int>get_next_ori(string p){
vector<int>next(p.size(),0);
next[0]=-1;
int k=-1,j=0;
while(j<p.size()){
if(k==-1||p[j]==p[k]){ //k在最前或者模式串两个p和j位置相等
next[++j]=++k; //j下一个位置不匹配的话就退回到k的下一个位置,因为j之前和k之前的匹配
}else{
k=next[k] //如果k不在最前并且模式串不等,k的位置在往前回退到和k匹配的位置next[k]
}
}
return next;
}
/*
上面找next数组方法在T:ABACBC P:ABAB的时候第3位C和B不匹配,会退到next[3]=2,但是T中的AC和P中的前面两个字母AB还是不匹配,因为P:ABAB的p[j]=p[next[j]],
所以回退回去还是一样的字母,肯定还不匹配,这个时候直接在回退到next[k]就可以,如果p[++j]!=p[next[++j]](即p[++j]!=p[++k])的话,可以直接设置next[j]=k
*/
vector<int>get_next(string p){
vector<int>next(p.size(),0);
next[0]=-1;
int k=-1,j=0;
while(j<p.size()){
if(k==-1||p[j]==p[k]){
if(p[++j]==p[++k]){
next[j]=next[k];
}else{
next[j]=k;
}
}else{
k=next[k]
}
}
return next;
}
int KMP(string t, string p){
int i=0,j=0;
vector<int>next=get_next(p);
while(i<t.size()&&j<p.size()){
if(t[i]==p[j]){
++i;
++j;
}else{
j=next[j];
}
}
if(j==p.size()-1)
return i-j;
else
return -1;
}