KMP算法个人理解总结

关键点:公共前后缀字符串

1.首先按照BF比较后,出现的那个不匹配的字符往前找,比如图中是AB。每次要取最长公共前后缀字符串,比如图中最长的是AB。
在这里插入图片描述

2.然后,把最长前缀移到最长后缀的位置,再从最长后缀开始比较。

在这里插入图片描述
这是按照移动模式串(子串)的思维来的。实际上操作是这样:

每次开始比较的编号,等于最大公共前后缀长度+1

如图中,到了模式串的第七个了,往前找,最大公共前后缀长度是1,这个时候把前缀移到后缀的位置,即将1移到6,那么接下来就是2号位与主串当前位比较。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

前后缀长度为n,则n+1号位于主串当前位置比较

这样以来,就得到了next数组

在这里插入图片描述
在这里插入图片描述
比如刚才next[7]=2

前后缀长度为n,则n+1号位与主串当前位置比较
前后缀长度为1,则2号位与主串当前位置比较,所以next[7]=2

next[i]表示模式串中,前面长度为i的串的公共最长前缀和后缀长度

一旦在匹配的时候在某个位置失配之后,直接依靠next数组跳到相同后缀的前缀部分。(相当于后缀的下一个匹配失败,则直接将位置跳到前缀的部分,因为我们next数组已经预处理了,O(1)实现。),

这时候继续比较该位置和前缀的下一个字母是否匹配,不匹配继续按上面的步骤跳转,匹配则匹配下一个字母直到完全匹配。

匹配失败相当于后缀的下一个匹配失败了,我们就可以直接跳到与后缀相同的前缀,此时前面依然是完全匹配的,继续比较下一个。

/*计算当前要匹配的模式串的next数组*/
void get_next(String T,int *next){
	int i,j;
	i=1;
	j=0;
	next[1]=0
	while(i<T[0]){  //T[0]表示模式串的长度
	
/*T[i]表示后缀的单个字符,T[j]表示前缀的单个字符
 *如果后缀字符和前缀字符相等,最后就得到一个next数组某一位的值*/  
		if (j==0||T[i]==T[j]){
			++i;
			++j;
			next[i]=j;
			}
		else
			j=next[j];	//若字符不相同,则j值回溯
			
	} 
}

/*执行KMP算法*/
int Index_KMP(String S,String T,int pos){
	/*i用于主串S当前位置的下标志。若pos不为1,则从pos位置开始匹配*/
	int i=pos;
	/*j用于模式串T当前位置的下标值*/
	int j=1;
	/*定义一个next数组*/
	int next[255];
	/*求模式串T的next数组*/
	get_next(T,next);
	
	/*若i小于S的长度,且j小于T的长度,则持续循环*/
	while(i<=S[0]&&j>=T[0]){
	/*两字母相等则继续(相对BF增加了j=0判断)*/
		if (j=0||S[i]==T[j]){
			++i;
			++j;
		}
		else {
		/*指针后退后重新开始匹配
		 *即:j退回合适的位置,i值不变*/
			j=next[j];
		}
	}
	if (j>T[0])
		return i-T[0];
	else
		return 0;
}

普通的BF暴力比较:

  • 对主串的每一个字符作为子串开头,与要匹配的字符串进行匹配。
  • 对主串做大循环,每个字符开头做子串长度的小循环,直到匹配成功or全部遍历完成。

实现代码:

/*返回子串T在主串S中第pos个字符后的位置。
 *若不存在,则函数的返回值为0 
 **T非空,1<=pos<=StrLength(S) */
 int Index(String S,String T,int pos){
    /*i用于主串S当前位置的下标志。若pos不为1,则从pos位置开始匹配*/
	int i=pos;
	/*j用于模式串T当前位置的下标值*/
	int j=1;
	
	/*若i小于S的长度,且j小于T的长度,则持续循环*/
	while(i<=S[0]&&j>=T[0]){
	/*两字母相等则继续*/
		if (S[i]==T[j]){
			++i;
			++j;
		}
		else {
		/*指针后退后重新开始匹配
		 *即:i退回到上次匹配首位的下一位,j退回到模式串T的首位*/
			j=next[j];
		}
	}
	if (j>T[0])
		return i-T[0];
	else
		return 0;
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值