数据结构KMP算法

cover

温馨提示:本篇属于总结,难免有疏漏和错误,如有发现建议直接囸作者,欸嘿


hutao


课上老师提到了KMP,下来了解了一下——md感觉瞬间懵逼(这就是马鹿吗i了i了)

KMP简介是这样的:

a

其中对核心要素next数组是这么介绍的:

b

c

最核心的next求法明白了,基本上KMP就没问题了。但是不幸的是,这玩意儿特别绕……

最长相等前后缀:

我们先看一下一个例子:abbcbabcc

这里对于他每一位字符而言,都会有一个对应的最长相等前后缀,针对倒数第二个c而言,我们可以画个图:long

红框对应的就是一对最长相等前后缀,注意这里的“对称”并非是镜像的,而应该是以“a”,“a b”为整体的中心对称。

现在再回到next求法上面。

关于NEXT:

next

这里的方程其实给人一种动态规划的状态转移方程的感觉(然而这个其实不是),但是问了一些ACM大手子,他们认为确实用了动态规划的一些思想但是缺少最优子结构什么的……

我觉得KMP有dp的思想,但不能算dp,你可以认为它做了两个事情:构造状态转移关系和根据关系转移,但是并没有明确的最优子结构和转移方程,硬要说的话,更接近记忆化搜索或者自动机

上面定义中,next[0]=-1是为了算法方便做的改动(实际j=0和j=-1都对应0)

在这个过程中,最重要的其实就是确定当前的Max{k},我们先看看GetNext代码:

GetNext

next[j]=k是记录当前最长相等前后缀长度,但是k=next[k]呢?这里就是理解这个函数的最大障碍,要弄清楚这个原理,我们再看看字符串中的对称:
$$
比如“abcdeabcdef”这个字符串
$$
字符串中“e”元素对应最长相等前后缀其实就是“abcde”,我们可以这么划分一下:

【abcde】【abcde】f

此时元素“f”出现了不匹配,那么我们就要找到一个新的最长相等前后缀,而这个新的最长相等前后缀肯定是小于“abcde”且除新的“f”元素以外都包含于“abcde”的,此时由于【abcde】【abcde】f中两个“abcdef”彼此对称,我们就可以把k回溯至开头的“abcde”后进行判定。

如此反复调用之前记录过的next[k]数据,即可求得新的最长相等前后缀。这里有两篇教程:

https://blog.csdn.net/weixin_34080571/article/details/93982239?ops_request_misc=&request_id=&biz_id=102&utm_term=KMPnext&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-4-93982239.first_rank_v2_pc_rank_v29

https://www.cnblogs.com/dusf/p/kmp.html

BMP的优化:

实际上,现在我们一般用的BMP算法与上面我们推导出来的还有一些细微的不同——BMP还可以进一步优化,省去一些不必要的过程。

这里我们看一下目标串与模板串进行比对的函数:

betterKMP

其实我们的优化就是利用中间标红的“j=next[j]”,对GetNext函数进行优化

在比对过程中,可能会出现这样的状况:

search

可以看到其实“d”在与“c”判断后,接下来几个连续与“a”的判断是多余的,因此要更改判断方式使相同的字符不会被重复选取。

GetNext

上图红色部分的意思是如果有t[j]==t[k]了,那么就说明KMP函数中调用next[j]肯定会出现重复,于是我们就直接跳过他调用next[k](若再出现一致则重复递归)。

附上详细讲解:

https://zhuanlan.zhihu.com/p/105629613

KMP算法大致就是这样运行的,建议再做两道题巩固一下o(* ̄▽ ̄*)o~


好了,话也说完了,那差不多就该

IMG_2662