问题描述:
给出一个文本串S和一个模式串P,判断P是否在S中出现,若出现返回模式串中的位置。
暴力匹配算法思想
假设当前文本串遍历到i,模式串遍历到j:
则
1.若s[i]==p[j]则文本串和模式串继续匹配
++i;
++j;
2.若s[i]!=p[j]则文本串和模式串进行回溯后再匹配
j=0;//模式串回到开头
i=i-(j-1)=i-j+1;
3.经过若干次1,2过程的匹配知道文本串或模式串遍历完,则判断j?plen i-j:-1;
代码如下:
int ViolentMatch(char *s,char *p){
int slen=strlen(s);
int plen=strlen(p);
int i=0;
int j=0;
while(i<slen&&j<plen){
if(s[i]==p[j]){
++i;
++j;
}
else{
j=0;
i=i-j+1;
}
}
if(j==plen) return i-j;
return -1;
}
2.KMP匹配算法思想
(1)整体过程
假设当前文本串遍历到i,模式串遍历到j,
则
1、若j==-1或s[i]==s[j],则文本串和模式串继续向后匹配
++i;
++j;
2.若j!=-1且s[i]!=s[j],则文本串不向前回溯即i不变,但模式串j向前回溯到next[j]的位置。
j=next[j];
3.经过若干次1,2过程的匹配知道文本串或模式串遍历完,则判断j?plen i-j:-1;
int KmpSearch(char *s,char *p){
int slen=strlen(s);
int plen=strlen(p);
int i=0;
int j=0;
while(i<slen&&j<plen){
if(j==-1&&s[i]==p[j]){
++i;
++j;
}
else{
j=next[j];
}
}
if(j==plen) return i-j;
return -1;
}
(2)next数组计算过程
假设当前存在p0p1...pk-1=pj-kpj-k+1...pj-1
1.若当前存在p[k]==p[j],则next[j+1] =next[j]+1;
2.若当前p[k]!=p[j]则k向前回溯k=next[k];
代码如下:
void GetNext(char *p,int next[]){
int k=-1;
int j=0;
next[i]=0;
int plen=strlen(p);
while(j<plen-1){
if(j==-1||p[k]==p[j]){
++k;
++j;
next[j]=k;
}
else{
k=next[k];
}
}
}
(3).优化Next数组的计算过程
主要原因是:
如S:abacd P:abab 当s[3]和P[3]匹配失败时回溯到s[3]和p[1]匹配此时还是失败的从而影响了匹配效率,此时应该继续向前回溯,优化过程则是在计算next时递归向前回溯。
void GetNext(char *p,int next[]){
int k=-1;
int j=0;
next[i]=0;
int plen=strlen(p);
while(j<plen-1){
if(j==-1||p[k]==p[j]){
++k;
++j;
if(p[k]!=p[j]){
next[j]=k;
}
else{
next[j]=next[k];//优化过程
}
}
else{
k=next[k];
}
}
}
总体来看,KMP算法的时间复杂度O(m+n)空间复杂度O(1)。