您的位置:首页 > 其它

KMP算法推导

2015-06-16 21:42 363 查看

一个问题

有一个主串S1,一个子串S2,如何判断主串S1中是否存在子串S2 ?

朴素模式匹配算法

我们举个例子

主串S1:
abcdefgab


子串S2:
abcdex


朴素模式匹配法的原理:

设i,j 分别表示主串S1与子串S2上的第i,j 个元素。i,j 均初始化为1

1. S1的第i个元素 与 S2的第j个元素进行对比,如果相同,执行步骤 2 。如果不同,执行步骤 3

2. i++, j++ , 重复步骤 1

3. j = 1 , 执行步骤 1

。。。

直到找到子串 或 主串被遍历

观察朴素模式匹配过程:

1.



2.



3.



4.



5.



6.



朴素模式匹配的步骤为1~6

我们观察一下子串S2:
abcdex
,首字符
a
与后边的
bcdex
中的字符均不相等

当第1步前边的
abcde
已匹配,而S1中的f 与 S2中的f 不匹配,执行了第2步

由于之前b已经与S1中的第二个元素匹配,b与a不相等,则没必要有第二步

同理,步骤3 4 5均不必要

或许会觉得其实也没什么。。。

假如主串为:00000000000000000000000000000000000000000000000000000000001

子串为:00000000000000001

朴素模式匹配法将会耗费大量时间,效率低

KMP匹配算法

正如上边所说,我们应该省去一些不必要的匹配,这也正是KMP算法产生的根本原因

我们可以在发现f不与x匹配时,由步骤1直接跳到步骤6

因为子串
abcdex
前边的
abcde
中,a与他们均不相同

假如子串后遍也有a呢?

我么再来看个例子:

主串S1:
abcabcabc


子串S2:
abcabx


朴素模式匹配法步骤如下:

1.



2.



3.



4.



5.



6.



我们可以跳过步骤2 和步骤3 ,原因就不多说了

然后观察步骤4 步骤5

在子串中第一位的a与第四位的a相等,第二位与第五位同为b

由于步骤1中已经匹配了前5 个元素,所以步骤4 步骤5 也可以省去,不需要再比较了

因为肯定也是相等的(之前比较过了,还判断什么)

最后结果:只需要步骤1 与 步骤6

一个发现

经过一番推到后的匹配步骤中

- 在步骤1 时,主串的下标i 为6

- 在步骤6 中,主串的下标i 还是6

朴素模式匹配中,主串的下标i 是不断地回溯的

经过我们的推导,发现这种回溯是不必要

我们的KMP算法就是为了让这些没必要的回溯不发生

如何实现KMP算法呢?

既然主串的i 不需要回溯,那么我们就要考虑子串下标j 的变化了

在我们之前的两个例子中,屡屡提到子串中首字符与后边字符的比较

如果发现有相等,则j 就会有不同的变化

所以j 的变化与主串无关,而与子串中的重复有关

有什么关系呢?

比如第一个例子中,子串为:
abcdex


没有任何的重复,所以j直接由6 变为1

第二个例子中,子串为:
abcabcx


前缀
ab
与 后边x 之前的串的后缀
ab
相同

则j 由6变为了3

规律:j 的变化取决于当前字符之前的串的前后缀的相似程度

一个让人看着发迷的公式

我们把串各个位置的j 值的变化定义为一个数组next,next长度为子串的长度

然后我们有了这样的定义:



先写到这儿,稍后写next数组的推导 :)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: