KMP算法的一些细节

来源:互联网 发布:网贷安卓源码 编辑:程序博客网 时间:2024/06/03 20:22

此篇记录了我学习KMP算法时的迷惑和解决过程

(本篇适合学习KMP算法之后,对算法尚有些迷惑的朋友,欢迎大家批判)


1、第一个疑问:KMP算法是否一定能求出正确的首个匹配下标(匹配字符串的第一个字符的下标)

因为KMP算法不像暴力求解算法一样是一个一个字符行进的,有点类似跳跃的行进,跳过了不需要匹配的字符,我产生了一个疑问,在行进的过程中是否会遗漏本可以匹配的字符串,导致得到的匹配下标不是首个匹配下标,而是第二或第三第四个


反证,假设不能。即存在一个被忽略的更小的下标。

          k

A B A B A A B........

A B A A B          ------>黄色为匹配失败处


   i   h  k           (i是假设的,h为最长前缀开始处)

A B A B A A B........

       A B A A B   ------>不同于暴力求解一位一位右移,而是类似“跳跃”。红色处为最长前缀,黄色处继续匹配

假设我们会遗漏一个“更小的匹配下标i”,使得文本txt[i]~txt[i+length] (length为模式串长度)与模式串pat[0]~pat[length]匹配,那么txt[i]~txt[k]一定是比我们当前的“最长前缀txt[h]~txt[k]更长的前缀,则与“next数组保存的是最长前缀”相矛盾,故不可能存在更长的前缀,即i不存在。

证得:我们不会遗漏一个更小的匹配下标


2、next数组的求法

01234k678910 j j+1ABGABBABGABGH-100012012345?       

                            next[k] = 2
                                              

第一行为模式串下标,第二行为模式串,第三行为next值

我们现在要求next[j+1],我们容易知道,如果pat[k] == pat[j],使得pat[0]~pat[k] == pat[j-k]~pat[j]的话,

那么next[j+1] = next[j]+1

那要是不等于呢?即pat[k] != pat[j]

通过学习,我们知道,要比较pat[next[k]]和pat[j],如果pat[next[k]] == pat[j],则next[j+1] = next[k] + 1

问题就是,为什么是比较pat[next[k]]和pat[j] ,为什么是next[k]??????


看上图,黄色标记处pat[k(5)] = B和pat[j(11)] = G匹配失败,而next[k] = 2,pat[next[k]] = pat[2] = G,最长前缀长度变成了3,即A B G,是可以匹配的最长前缀(pat[0~2] == pat[9~j])


事实上,我们可以证明这一事实的正确性

因为匹配失败,那么我们要寻找的最长前缀肯定是一个比A B G A B(0~k-1)更短的前缀

而且这个更短的前缀,一定是包含在A B G A B(0~k-1)里(因为必须从第一个字符开始,且长度更短


仔细思考,我们得出这样一个结论:

我们假设这个最长前缀存在(pat[j+1]前的最长匹配前缀),设为str

则str - pat[j] 的长度一定等于next[k]

看下图

该图中str = ABG, pat[j] = G

(一定要注意观察和思考下面的三个红色A B)

01234k678910 j j+1ABGABBABGABGH-100012012345?

                   next[k] = 2


我们先不管pat[j],先寻找pat[j]前长度稍短于k的前缀(实际上这个稍短前缀的长度就是next[k]),然后再加上pat[j]得到新前缀,得到next[j+1] = next[k]+1。上例中这个稍短前缀就是AB,pat[j] = G。

为什么稍短前缀的长度就是next[k]?

因为pat[0] ~ pat[k-1]和pat[j-k]~pat[j-1]都是一样的(已经匹配过)

那么str - pat[j]必然和pat[k]前的子串一模一样(而且这两个串都一定等于一个前缀,在上例中就是AB

由于我们要使得str - pat[j]最长,那这个最长的长度一定就是next[k]

最后,我们再判断是否pat[next[k]] = pat[j],如果等于,则得到next[j+1] = next[k] + 1 (AB + G)

否则,再继续递归寻找,下一步判断pat[next[next]]。。。。道理同上


原创粉丝点击