KMP算法详解

来源:互联网 发布:淘宝怎样找妹子服务 编辑:程序博客网 时间:2024/06/13 05:29

在模式匹配中,除开最基本的暴力匹配之外,还有很多高效的方法,其中KMP就是其中一个经典算法,但这个算法思想晦涩难懂,我最开始学习,都直接放弃了,直接学的boyer-moore,后来还是觉得应该弄懂才行,为此,特地将我解决的思路分享出来。

设,需要在text中查找模式pattern出现的位置,KMP的思想关键在于前面匹配过之后,是会留下有用信息的,这样后面可以直接跳过一些查找,如图所示:


当匹配到红色处失败之后,我们希望能多往前移动一些,且利用前面已经匹配过的信息,这里的做法是,在当前已经匹配成功的这一段(红色之前)中,如果我们能在这一段的最前面找到一段(称为前缀),然后在这一段后面找到一段(称为后缀),而这两段刚好相同(图中蓝色的两段),且不存在更长的相等段(即两段蓝色的加上棕色的之后,新的两段不相等),如果找到这样的蓝色段,那么我们移动的时候就可以直接移动到下面那个图的位置,即再往前就是无用的比较(不存在相等的段了,因为如果存在,那么蓝色段会变长),再往后,可能会错过正确的。而移动到这个样子之后,我们也可以不比较蓝色段,直接从上次出错的地方开始(即text上红色段对应下来的位置,直接修改pattern的指针),当pattern指向第一个元素,仍然不匹配时,将text往前移动一次,直到pattern遍历完(找到)或者text遍历完(未找到)。

那么现在问题就只剩下求每个位置在它之前的那段中的最长相等前缀了(我们称之为next值吧)。这里这样考虑,结合下图:

                                                                                 

红色是我们想要求出next值的位置,蓝色表示这个位置前一个位置已经匹配的最大长度,那么,如果绿色的值和红色相等,那么毫无疑问,当前红色的next值就等于它前一个位置的next值加1;如果红色和绿色不匹配呢?结合下图来看:


其实进一步,我们可以将蓝色再分开,把蓝色看成一个独立的串,那么蓝色里面肯定也存在两个像上图一样相等的粉色,所以,当红色和绿色不相同时,如果红色和橙色相等,那么红色的next值就是橙色的位置,而橙色的前一个位置,其实就是绿色前一个位置的next值,next[i]=next[next[i-1]]+1,如果红色还不等于橙色,继续下去,直到都不满足,那么红色的next值就是-1(第一个位置的next值也是-1,其实next值就是表示和它相等的最大长度的前缀的结束坐标)。

具体代码如下(python实现,next函数是求pattern的next值):

#KMPdef NextList(pattern):    next=[]    next.append(-1)    for i in range(1,len(pattern)):        index=next[i-1]        while index>=0 and pattern[i]!=pattern[index+1]:            index=next[index]        if pattern[i]==pattern[index+1]:            next.append(index+1)        else:            next.append(-1)    return nextdef KMP(pattern,text):    next=NextList(pattern)    i,j=0,0    while i<len(pattern) and j<len(text):        if pattern[i]==text[j]:            i+=1            j+=1        elif i==0:            j+=1        else:            i=next[i-1]+1    if i==len(pattern):        print("find it, the position is "+str(j-i))    else:        print("not find it")


0 0
原创粉丝点击