LEETCODE28
1.简单的模式匹配算法
/*
i=7
4 |
a b a b c a b c a => 回到i=4(3下一位)的位置即i-j+2
a b c a c
|
j=5
*/
//S[0],T[0]存放长度
int Index(SString S,SString T){
int i=1,j=1;
while(i<=S[0]&&j<=T[0]){
if(S[i]==T[j]){
++i;
++j;
}
else{
i=i-j+2;;
j=1;
}
}
if(j>T[0])
return i-T[0];
return 0;
}
2.KMP算法:
kmp算法思想:
/*
对于模式串str:_____abcad______f,______为最长相同前后缀;
与主串模式匹配中的一个结果:
i
..._____abcad______f...
_____abcad______d...
^
j
模式匹配到模式串^位置,与主串不同,正常的做法是模式串从开始重新比较;
kmp做法:
i
..._____abcad______f...
______abcad______d...
^
j=next[j-1]+1 (*)
主串和模式串到出错之前都是一样的,且______也都是一样,
______部分都一样,就相当于比较过了,直接从模式串^处开始比较;
*/
next[]:
/*
next[i]为str[0~i]字符串最长相同前后缀长度-1(0就是没有减1=>-1);
i : 0 1 2 3 4 5
str : a b a a b c
next: -1 -1 0 0 1 -1
求next思路:
1).求出str[0-i]的最长相同前后缀,结束时next[i]为str[0-i]最长相同前后缀中前缀结尾位置;
2).next[i]要的是i处匹配失败i要去的位置,修改为next[i]=next[i-1]+1,参考kmp思想部分;
具体方法:1)
初始化next[0]=-1,k=-1;
假设已知next[p]=k,即此时'______'即为str[0-p]的最长相同前后缀
______abcs______
| |
k p
求next[p+1]的两种情况,,next[p]=k:
1.str[p+1]==strl[k+1],那next[p+1]=k+1;
______abcs______a
| |
k+1 p+1
2.str[p+1]!=strl[k+1],回溯k=next[k]继续比较;
______abcs______b
| |
k+1 p+1
即要找到str[0-p]的所有相同前后缀,由*长到短*看前缀的下一位是否与str[p+1]相等,
若相等即找到了str[0-(p+1)]的最长相同前后缀(这是目前最长的符合条件的,那么长度+1也是最长的),
关键是要找到str[0-p]的所有相同前后缀。
原理:
1.短的相同前后缀一定包含在长的相同前后缀里;
2.设str的相同前缀为A,后缀为B,则(A=B)=>A中包含了str的开头和尾部=>A的相同前后缀也为str的相同前后缀;
3.若A为str的*最长*相同前后缀的前缀,那么A的最长相同前后缀就为第2长;
(由2.3知道若要求str的*所有*相同前后前缀,只要有了最长前后缀就行了,不必管中间部分)
=>可以用回溯的方法找到所有相同前后缀
*/
//next[]实现方法:
void get_next(int *next,char* T,int len){
//初始next[0],k,由于next[i]=k,所以设k为-1
next[0]=-1;
int k=-1;
for(int i=1;i<len;i++){
//一直回溯,在k>-1的条件下找T[k+1]==T[i]
while(k>-1&&T[k+1]!=T[i])
k=next[k];
//到这要不是找到了,要不就是k=-1了
if(T[k+1]==T[i])
k=k+1;
next[i]=k;
}
}
//(*)修改next,用于KMP,现在next[]存放的是相同前后最长度,并不是匹配失败后'j'要去的位置(0开始);
//具体方法看kmp算法思想部分(*);
//对于特殊的next[0]位置单独看:若在这个地方出错了,即两个str第一个就不一样,那么就要'i'后移,'j'清零,
//所以置next[0]=-1,这样在KMP算法部分就可以直接通过{++i,++j}=>i=i+1,j=0,也就不用单独判断j的情况,简练;
for(int i=len-1;i>0;i--){
next[i]=next[i-1]+1;
}
KMP算法实现:
void get_next(int *next,char* T,int len){
next[0]=-1;
int k=-1;
for(int i=1;i<len;i++){
while(k>-1&&T[k+1]!=T[i])
k=next[k];
if(T[k+1]==T[i])
k=k+1;
next[i]=k;
}
for(int i=len-1;i>0;i--)
next[i]=next[i-1]+1;
//next[0]=-2; //对应KMP()注释部分
}
int KMP(char* T,int tlen char* S,int slen) {
if(slen==0)
return 0;
get_next(next,S,slen);
int i=0,j=0;
while(i<tlen&&j<slen){
//j==-1说明与模式串第一位就不一样,直接往后走=>i=i+1,j=0
if(j==-1||T[i]==S[j]){
++i;
++j;
}
//有问题就去j该去的地方
else
j=next[j];
}
/*
//while()中也可以将对j判断单独拿出来:
while(i<tlen&&j<slen){
//与模式串第一位就不一样
if(j==-2){
++i;
j=0;
}
else if(haystack[i]==needle[j]){
++i;
++j;
}
else
j=next[j];
}
*/
if(j>=len)
return i-len;
return -1;
}