让人蛋疼的KMP算法

来源:互联网 发布:手机淘宝个人主页在哪 编辑:程序博客网 时间:2024/06/05 00:29

昨天刷题再次偶遇KMP算法,这个算法之前来来回回折腾了好多次了,不理解好像理解了能写代码实现了又不理解又好像理解了。。。。。。。

今天在这里整理下我个人对KMP算法的理解也给想了解这个算法的朋友一点参考。

在写之前先说明一下本文中的图片除最后一个其它均来自http://blog.csdn.net/v_july_v/article/details/7041827,这篇博客讲的挺好,大家可以看一下。

 

说到KMP算法必须从字符串匹配说起。什么是字符串匹配呢?就是给你个文本串和目标串让你找目标串在文本串中出现的位置,这听起来好像很简单直接用暴力法就可以。


暴力法如上图,第一行为文本串第二行为目标串,这里定义文本串的长度为n,目标串的长度为m以[start,end]中的每个字符做头与目标串进行一一比较,当两个子串相等时返回字符串头字符的索引。这种方法显然正确但是忽略了我们在比较过程中获取的一些有用信息。

比如当比较进行到下图这个状态时:


目标串的前m-1个字符都和文本串匹配,第m个不匹配了,按照暴力法步骤接下来我们会进入下图这个状态


感觉好像也没什么就得这样。但是经过进一步的推理我们会发现有些比较是没必要进行的我们完全可以直接跳到这个状态:


为什么能这样跳呢,这样跳能保证一些解不被漏掉吗???

再解释原因之前必须引入前缀后缀的概念。比如字符串abc其前缀就是a,ab,abc其中真前缀为a,ab。同理真后缀为c,bc下面为了书写方便用前缀后缀来表示真前缀和真后缀。前缀后缀的长度即为这个子串字符的个数。我们这里非形式化的对最长公共前后缀长度做个定义:

字符串的有前缀集合和后缀集合,两个集合中可能会存在相等的串,在这些相等的串中长度最长的我们成为最长公共前后缀长度。例如对串ABAB前缀集合{A,AB,ABA}后缀集合{B,AB,BAB}

最长公共前后缀为AB长度为2.

有了这个定义之后我们就能得到这样一张表:


下面我们解释下上面这张表:第一行为字符串中的每个字符,第二行为该字符前面的字符串(不包括该字符)最长公共前后缀长度。因为对首字符A来说考虑其前面的字符串没有意义故这里标记为-1.对于最后一个字符D其前面的字符串为ABCDAB很明显其有个前缀字符串AB后缀字符串AB且两者相等所有最长公共前后缀长度为2.

好了回到上面的问题,为什么KMP算法就敢直接这样跳呢,我们先看下用暴力法不跳的时候。

如果按暴力法的话下一个状态如下:


正如图中说的方框内的字符串上下相等,才有可能匹配。仔细看下方框内的是什么东西呢,是不是ABCDAB的前len-1(这里ABCDAB的长度用len表示)个前缀和ABCDAB的后len-1个后缀比较呢,如果相等就有可能是不相等就不可能是。不是的话就再往后即用用目标串匹配以当前字符B的下一个字符开头的字符串。此时是ABCDAB的前len-2个前缀匹配ABDCAB的后len-2的前缀。。。。。。。。Len-3。。。。。。。。Len-4.。。。。。。。。。。。。。。。。。。。。KMP算法的精髓就是直接提前排除了不可能是的情况。它是怎样做到直接排除的呢,还记得上面那个表格吗??D对应的为2ABCDAB的最长前后缀长度为2.所有len-1时肯定不靠谱(很明显这里len=6.

所以我们直接跳到len-4=2时的状态就可以,已知最长公共前后缀长度为2,所有前两个肯定是匹配的(前缀=后缀),直接从第三个开始比较就可以,这个状态如下图:


总结一下就是这样:我们可以先计算一张表,这张表的内容是什么呢,是每个字符前面串的最长公共前后缀。然后kmp算法可以根据这张表跳跃式前进,为什么说是跳跃式呢,这是

相对于 暴力法来讲的。当匹配到某个字符匹配失败时根据表中该字符所对应的值直接跳到相应位置。(实现跳跃的一个原因是在建表的过程中我们已经进行了很多次比较)。

最后讲一下如何建表:

这也是让人很头疼的一个问题,我们这里只概述一下其基本原理。我们用next数组来存储这张表。对于首字符由于其前面是空串我们定义next[0]=-1(这里写成0也行只是代码实现时细节部分要有相应考虑);对于第一个字符其前面串只有一个字符并且其真前缀会空所以next[1]=0(这里假定目标串至少有两个字符)。然后我们可以有next[k]的值来推next[k+1]的值。

如下图:

蓝色部分是相等的,并且蓝色部分的长度就是对应的值,对于next[],如果红色部分等于黄色部分即这时候太好了但是当这俩货不相等时就麻烦了。如下图:


如图所示蓝色部分为索引k之前字符串的前缀和后缀且两者相等,如果,此时我们把上面的字符串这样看:

蓝色部分都相等,再到下一个不相等了是不是和字符串匹配二十分的类似呢,带有后缀的这个第一行的看成模式串,下面的这个看成目标串。不相等了根据之前计算的表跳跃式匹配,只是我们这里追求的是最多能匹配几个而不是能不能完全匹配,方法是一样一样的。

 

就到这吧,水平有限难免有疏忽望批评指正。





0 0
原创粉丝点击