KMP算法

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值