KMP的复习记录
这位同学说的好,知识的吸收是需要拆分再联通的,回首一些博客会看不懂,可能也是一些联系断掉了,可能在博客里省略了不少当时很清楚但以后就会忘记的内容,今后应尽量避免。
也许文字并不一定都要自己写,但一定要连贯,上下文要饱满,今天就好好记录一下KMP。
目标是以后看这篇博客,就能回想起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数组都是这样
三、匹配思路和实现代码
因为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数组的求法是通过模板串自己与自己进行匹配操作得出来的。
这里也得画图理解,看文章的即可。
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
五、后记
写完之后感觉。。。其实并没有那么简单就能把这个时候的状态记录下来。。。
但可以把对一些问题的理解记录下来
同时也需要多回顾吧==
学习好难