KMP字符串匹配算法

来源:互联网 发布:win10 python环境搭建 编辑:程序博客网 时间:2024/06/04 19:04

今天学习了一下KMP字符串匹配算法。看的是July的博客从头到尾彻底理解KMP(2014年8月22日版),写得很详细。

有两个字符串,母串S,子串P,要在S中找到P。朴素的字符串匹配算法是一一比较两个字符串中的每一个字符,同时记录连续匹配的长度,该长度与P长度一致时说明在S中找到了P。若某个字符失配,则S的索引i和P的索引j都要回退已匹配的长度,然后以下一个字符为首字符继续匹配。时间复杂度为O(m*n),m和n分别为P和S的长度。

而KMP字符串匹配利用了P串中最长共同前后缀的信息,构造出一个next数组,用于在失配时指定P的索引j回退的长度,而S的索引i不需要回退。将时间复杂度降为O(m+n)。

具体代码和注释如下。为了说明next数组构建过程中的关键递归语句k=next[k],我使用了与July不同的用例。

/*2015.8.3cyq*/#include <iostream>#include <string>#include <vector>using namespace std;//朴素的字符串匹配,寻找主串S中的子串P,时间复杂度O(m*n)int strMatch(const string &S,const string &P){int n=S.size();int m=P.size();if(n<m)return -1;int i=0,j=0;while(i<n&&j<m){if(S[i]==P[j]){//该字符匹配i++;j++;}else{//失配,i回退j步到匹配的首字符,然后加1i=i-j+1;j=0;}}if(j==m)//全部匹配,返回P在S中的位置return i-j;return -1;}//KMP,时间复杂度O(m+n)//string S="AAACDAAAD ECDAACDAAEB";//string P= "AACDAAEB";//next数组: -10100120//P串AACDAAE与S串AACDAAA不匹配,j从6变为2,比较AAC与S串中间的AAAint kmpMatch(const string &S,const string &P,const vector<int> &next){int n=S.size();int m=P.size();if(n<m)return -1;int i=0,j=0;while(i<n&&j<m){if(j==-1||S[i]==P[j]){i++;j++;}else{j=next[j];//j=0时,若S[i]!=P[0],则j=next[0]=-1,结束递归}}if(j==m)return i-j;elsereturn -1;}//获取子串P的next数组//next[j]=k表示P[j]之前(不包括P[j])有长度为k的相同前后缀void getNext(const string &P,vector<int> &next){int len=P.size();next[0]=-1;int k=-1;int j=0;while(j<len-1){if(k==-1||P[k]==P[j]){k++;j++;next[j]=k;//该行换成下面4行,可在k缩小后得到同样字符时获得优化//if(P[j]!=P[k])//next[j]=k;//else//next[j]=next[k];}else{k=next[k];//缩短共同前后缀的长度//该句很关键,以AACDAAEB为例//next数组为: -10100120//计算B所对应的next[7]时,因P[2]!=P[6],AAC与AAE不匹配,则k=next[k],k从2变为1//意义为E前面虽然有长度为2的AA与字符串前缀AA匹配,但E与C不匹配,//于是只能缩短共同前后缀长度,利用E与C前面的字符串一致的信息,//结合next[2]=1,即C前面有长度为1的共同前后缀,将E前面的共同前后缀长度缩短到1,//这样就确定P[1]与P[6]前面是已匹配的,直接比较P[1]和P[6]即可,由于AA与AE又不匹配//k=next[k],k从1变为0,比较P[0]与P[6],A和E又不匹配,k=next[k],k从0变为-1//之后k++,j++,next[7]=0,也可见递归的退出条件是匹配或者k==-1}}}int main(){string s1="AAACDAAAD ECDAACDAAEB";string s2= "AACDAAEB";  //next数组为:-10100120int m=s2.size();vector<int> next(m);getNext(s2,next);for(int i=0;i<m;i++)cout<<next[i]<<" ";cout<<endl;cout<<"strMathch:"<<strMatch(s1,s2)<<endl;//输出13cout<<"KMP:"<<kmpMatch(s1,s2,next)<<endl;//输出13return 0;}


0 0
原创粉丝点击