KMP相关

今天刷到KMP算法
具体的力扣28 找出字符串中第一个匹配项的下标,写篇文章方便自己后续复习
例如文本串aabaabaaf ,模式串aabaaf。在匹配过程中我们在f这里不匹配了,那么我们就看f的前面。
前面是模式串的子串,子串的后缀是aa,我们就找到与这个后缀相等的前缀的后面——也就是b。所以我们要知道最长相等前后缀,这样我们在遇到不匹配的位置的时候呢,我们就找前面的这个子串的最长相等前后缀。
aabaa的最长相等前后缀就是2,所以跳到b。

那么什么是前缀,什么又是后缀,拿aabaaf举例。
前缀是包含首字母不包含尾字母的所有字母,所以有如下:

a
aa
aab
aaba
aabaa

aabaaf就不是前缀,不包含尾字母。
后缀是只包含尾字母,不包含首字母:

f
af
aaf
baaf
abaaf

知道了前缀和后缀,我们要求模式串子串的最长相等前后缀。
其中a aa aab aaba aabaa 都是模式串的子串,我们就来找子串的最长相等前后缀

a -> 0
aa-> 1 (a)
aab -> 0	
aaba -> 1 (a)
aabaa -> 2  (aa)
aabaaf -> 0

由此我们就得到了这个前缀表 010120

文本串:  a 	a	b	a	a	b	a	a	f
模式串:  a	a	b	a	a	f
前缀表:  0	1	0	1	2	0

当我们在f不匹配后,我们要找f前面的最长相等前后缀 也就是2,2意味着这里有个后缀aa,前面也有一个相等的前缀aa。如果我们在后面不匹配了冲突了,那么我们就要找到与其相等的前缀aa的下一个元素重新开始匹配。那么这个重新开始匹配的元素坐标是多少呢,其实就是其最长相等前后缀的长度.这就是前缀表的作用。
那么前缀表怎么求呢 这里直接给出代码:

int m = pattern.size();
vector<int> next(m,0);
//这里的i是模式串遍历的指针,max_len是最长相同前后缀的长度
int i = 1;
int max_len = 0;
//下面我们开始遍历,前指针为最长相同前后缀的指针,后指针为我们遍历模式字符串的指针
while(i < m){
	//如果遍历的时侯发现后指针与前指针的字符相同,我们就把max_len+1,代表后面的内容跟前面的内容相同。
	if(pattern[i] == pattern[max_len]){
		max_len++;
		i++;
		next[i] = max_len;
	}
	else{
		//如果遍历时候发现后指针与前指针的字符不同,那么看max_len的数值,
		//如果为0则代表前面没有跟现在的字符内容一样的,可以直接赋值0然后i++
		if(max_len == 0){
			next[i] = 0;
			i++;
		}
		//如果max_len的数值不为0,也就是现在的else情况:那么说明后指针的前一个字符跟第一个字符相同
		//(max_len=1,如果后指针的前两个字符跟开头的两个字符相同那就是max_len=2),所以我们要回退到当前指针的前一个字符,
		//来看前一个字符的最长相等前后缀。一定要注意这里i并不+1,i需要重新while循环来判断,例如下面 当后指针指到最后一个B的时候max_-len = next[3-1] =1,然后再次循环pattern[7] == pattern[1] 这是成立的,然后max_len++,i++ 结束循环。 
		else{ 
			max_len = next[max_len-1]
		}
//例子中子串与前缀表的对应关系。
A	B	A	C	A	B	A	B
0	0	1	0	1	2	3	0	
			

构建完next数组后,我们在根据next数组进行遍历就可以了,这里也分为主串指针和子串指针。
主串为haystack 子串为needle

int master = 0;
int sub = 0;
while(master < haystack.size()){
	if(haystack[master] == needle[sub]){
		sub++;
		master++;
	}
	//每相加一次都判断下是否把子串遍历结束了防止越界
	if( sub == strlen(needle){
		return master-sub;
	}
	//当主串指针和子串指针不相等时,先检查是否在子串第一个字符就不相等
	//sub >0说明不是在子串第一个字符就不相等,这时候next数组就派上用场了。直接把子串指针转移到前一个字符的最长相同前后缀
	else if(haystack[master] != needle[sub]&& ( master < n)){
		if(sub > 0){
			sub = next[sub-1];
		}
	//这里就是在子串第一个字符就不相等了,直接主串++就OK
		else{
			master++;
		}
	}
}

//如果sub的值等于子串的长度,那么说明sub已经遍历整个子串了,所以就返回master-sub,这个值是在主串中第一次出现子串的位置。

到这里KMP相关的next和遍历就结束了,如果后续在看不懂可以直接看这个视频 配合视频食用更佳。

 https://www.bilibili.com/video/BV1AY4y157yL/?share_source=copy_web&vd_source=dd22477739333dfa4121f1203f4948c9
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值