KMP的复习记录

这位同学说的好,知识的吸收是需要拆分再联通的,回首一些博客会看不懂,可能也是一些联系断掉了,可能在博客里省略了不少当时很清楚但以后就会忘记的内容,今后应尽量避免。

也许文字并不一定都要自己写,但一定要连贯,上下文要饱满,今天就好好记录一下KMP。

目标是以后看这篇博客,就能回想起KMP算法是什么,以及正确地实现。

但是其实下面这篇文章就写得很好,可以作为榜样,这里便结合作者的思路记录我的总结。

AcWing 831. KMP字符串 - AcWing - 四谷夕雨

一、基本内容

待解决的问题

字符串的匹配问题

模板题:831. KMP字符串 - AcWing题库

基本概念

核心思想

二、next数组

next数组的含义:对next[ j ] ,是p[ 1, j ]串中前缀和后缀相同的最大长度(部分匹配值),即 p[ 1, next[ j ] ] = p[ j - next[ j ] + 1, j ]。

其作用是加速匹配,会在下文中体现。

不同于常规数组,这里next数组下标从1开始,和这里的定义都是为了简化代码,不一定所有next数组都是这样

三、匹配思路和实现代码

匹配.PNG

因为1串等于3串,3串等于2串。所以直接移动p串使1到3的位置即可。

不过什么是“移动”?移动就是改变 j 的值,改变之后再让第 j + 1 个元素和第 i 个元素对齐。

这个操作可由j = next[ j ]直接完成。

移动之后的效果是S串和P串匹配了next[j]个字符,接着再判断S[i]和P[next[j] + 1]。

特别说明它们是否相等是需要进一步的判断的,尽管已经扫描过了一遍,但是我们并没有记录相关的信息。

最后,移动一次可能还能接着移,上述过程(把P串往前移)是可以一直重复,直至不能移,或者S[i]和P[j + 1]相等为止。

实现代码

for (int i = 1, j = 0; i <= m; i ++ ){      // 每次比较的是s[i]和p[j+1],因此要令j=0 
	while (s[i] != p[j + 1] && j) j = ne[j];// j 不等于 0 说明正在匹配;等于 0 说明刚开始或者失配,这时没有必要也不能回退
	if (s[i] == p[j + 1]) j ++ ;			
	if (j == n) {
		printf("%d ", i - j);	// 这里为什么是 i - j,最好结合图形理解
		j = ne[j];				// 题目要求找出所有匹配的串,所以这里还要回退
	}
}	

总的来说就三步:

  • 回退
  • 进位
  • 判断终点

四、求next数组的思路和实现代码

next数组的求法是通过模板串自己与自己进行匹配操作得出来的。

这里也得画图理解,看文章的即可。

next数组.PNG

for (int i = 2, j = 0; i <= n; i ++ ){		// 交错匹配,求ne数组
	while(p[i] != p[j + 1] && j) j = ne[j];	
	// 判断条件里的&& j,是由实际意义决定的,如果j=0,说明一个字符也没匹配,那也就谈不上失配了;
    // 无此条件将导致死循环ne[0]=0。 
	if (p[i] == p[j + 1]) j ++ ;			// 逐位匹配的过程 
	ne[i] = j;	// 这句话须结合图形理解
}

总的来说其实就三步:

  • 回退
  • 进位
  • 赋值ne

五、后记

写完之后感觉。。。其实并没有那么简单就能把这个时候的状态记录下来。。。

但可以把对一些问题的理解记录下来

同时也需要多回顾吧==

学习好难

posted @ 2022-10-09 16:43  tsrigo  阅读(14)  评论(0编辑  收藏  举报