对KMP的一些理解

蓝桥杯前夕。虽然被这比赛坑过,但该打的成就还是要打的。所以今晚就复习一下很久没有碰的KMP吧。

KMP是个很优秀的字符串匹配算法(废话),其时间复杂度为 O ( n + m ) O(n+m) O(n+m)

使用KMP进行匹配之前,需要预处理出来一个数组,名为next,顾名思义为失配后指针要移动到的下一个位置。

next数组的值还可以理解为(以当前字符的前一位为末尾)并且(和当前字符串的前缀相同)的最大字符串的长度。

举个例子:

      a b c d a b c d a b c e
next:-1 0 0 0 0 1 2 3 4 5 6 7 0

在这里插入图片描述

计算时采用双指针的形式,i在后面,j在前面。

首先规定next[0]=-1,因为next数组表示的是前一位结尾的字符串和模式串的最大公共前缀,所以0前面是-1,无意义。next[1]=0,因为它本身等于它本身无意义,不能给后面的计算带来帮助,所以置为0。

在这里插入图片描述

假设j前面的字符都已经和i前面的字符匹配了,那么当p[i]=p[j]时,next[i+1]=next[i]+1,也可以用j+1表示(上文高亮部分)。

p[i]!=p[j]时:

在这里插入图片描述

此时,以第i个字符为结尾的后缀(即p[i-next[i],i])和字符串p[0,j]不相同,因为最后一位没有匹配。按照暴力做法,此时应该让j归为0,i往前移j-1位准备重新比较。

但是观察next[j]可以发现,我们可以利用next[j]直接得知第i个位置前面的长度为next[j]的字符串(即"abc")和第j个位置前面的长度为next[j]的字符串是一样的。即(p[i-next[j],i-1]=p[j-next[j],j-1]),而p[j-next[j],j-1]又和p[0,next[j]-1]相同,所以此时可以直接认为最前面的next[j]位已经比较过了,现在轮到p[next[j]]p[i]比较了。在程序中的操作为j=next[j]i不变。

由此递推得到next数组。

进行匹配时同理,也是进行这种j=next[j]的操作来降低时间复杂度。

猜你喜欢

转载自blog.csdn.net/weixin_42856843/article/details/109125959