图解KMP算法中next数组的求解,含代码

本篇文章不涉及KMP算法的基本原理,且仅针对于最长相等前后缀长度的next数组的表示的计算

先看代码

void getNext(string p,int*next){
	int i=0,j=-1;
	next[0]=-1;
	while(i<p.length()){
		if(j==-1 || p[i] == p[j]){
			i++;j++;
			next[i] = j;
		}else{
			j=next[j];
		}
	}
}

基础

  1. next数组的值每次最多增一
  2. 当前位置的next数组的值取决于其之前的字符串
  3. 模式串的最后一位字符不会影响next数组的结果
  4. next[0] 一定为 -1,特殊取值,当首字母匹配失败则可进入下一轮判断
  5. next[1] 一定为 0,最长相等前后缀长度为0

i和j指针代表什么?

i指针用来标识已匹配后缀的后一个位置,同时也是最后一位已知next数组值的位置,其之前字母的关系都是可以确定的。
j指针标识已匹配前缀的后一个位置,其值等于next[i]
(因为在代码中是以0为起始下标,则next[i]最长相等前后缀长度可以完全对应数组下标)。
注: i所在位置的next数组的值一定是已知的

结合图示理解:

1.假定红色区域为下一位待确定数值的位置,即模式串第七个字母,其next数组的值完全取决于前6个字母。设i,j指针所处位置如下,next[i]=2,可知A部分和B部分是相等的,那么j此时应该指向下标2。
在这里插入图片描述
2.基于此,若pattern[i]等于pattern[j],则此时前后缀末尾匹配成功。那么则可确定红色区域的值,为next[i]+1(j+1)(这里的i,j还没有发生改变);也就是对应于代码中的i++;(指向待定位置),j++;(确定next数组的值),然后赋值。如下:
在这里插入图片描述
3.如若pattern[i]不等于pattern[j],则此时j指针应该回溯到次最长的相等前后缀的位置,即next[j]的值。假定这里next[j]=1.即可说明A部分中的两个字母相同,同理,B部分中的两个字母也相同(图中深绿色的部分):
在这里插入图片描述
这种情况下,继续重复判断即可。对应代码中j = next[j]。
4.若此时pattern[i]依旧不等于pattern[j],则j会继续回溯到当前next[j]标识的位置,即下标为0的位置。
5.如若还不相等,j的值则会变为-1,代表无公共前后缀,此时也相应执行i++,j++,i指向了待确定next数组值的位置,j的值0代表了最长相等前后缀长度,执行赋值操作后再依次确定之后的位置(本图示中即已结束)。
在这里插入图片描述

完整KMP代码(包含示例)

//KMP 
void getNext(string p,int*next){
	int i=0,j=-1;
	next[0]=-1;
	while(i<p.length()){
		if(j==-1 || p[i] == p[j]){
			i++;j++;
			next[i] = j;
		}else{
			j=next[j];
		}
	}
}
int KMPMatch(string text,string pat,int*next){
	int i=0,j=0;
	while(i<(int)text.length() && j<(int)pat.length()){
		if(j==-1 || text[i] == pat[j]){
			i++;j++;
		}else{
			j=next[j];
		}
	}
	if(j == pat.size()){
		return i-pat.size();
	}else{
		return 0;
	}
}

小tip: 在KMPMatch函数中,由于j的值可能为-1,而pat.length() 返回的是 size_t 类型,这是一个无符号整数类型,必须进行强制类型转换。

KMP算法是一种用于字符串匹配的高效算法,其的next数组是该算法的核心部分之一。next数组用于记录模式串每个位置的最长公共前缀和最长公共后缀的长度。 具体来说,next数组的定义如下: 1. next = -1,表示模式串的第一个字符没有前缀和后缀。 2. 对于模式串的每个位置i(1 <= i < 模式串长度),next[i]表示模式串前缀子串[0, i-1]最长的既是前缀又是后缀的子串的长度。 通过构建next数组,可以在匹配过程根据已匹配的前缀信息来决定下一步的移动位置,从而避免不必要的比较。 下面是构建next数组的步骤: 1. 初始化next = -1,j = 0,i = 1。 2. 当i < 模式串长度时,执行以下步骤: - 如果模式串的第i个字符与模式串的第j个字符相等,则令next[i] = j,i++,j++。 - 如果模式串的第i个字符与模式串的第j个字符不相等: - 如果j = 0,则令next[i] = 0,i++。 - 如果j != 0,则令j = next[j],回溯到上一个最长公共前缀和最长公共后缀的长度,继续比较。 构建完next数组后,可以根据next数组来进行字符串匹配,具体步骤如下: 1. 初始化文本串的指针i = 0,模式串的指针j = 0。 2. 当i < 文本串长度时,执行以下步骤: - 如果文本串的第i个字符与模式串的第j个字符相等,则i++,j++。 - 如果j = 模式串长度,则表示匹配成功,返回匹配位置。 - 如果文本串的第i个字符与模式串的第j个字符不相等: - 如果j = 0,则i++。 - 如果j != 0,则令j = next[j],回溯到上一个最长公共前缀和最长公共后缀的长度,继续比较。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值