KMP算法推导
2015-06-16 21:42
363 查看
一个问题
有一个主串S1,一个子串S2,如何判断主串S1中是否存在子串S2 ?朴素模式匹配算法
我们举个例子
主串S1:abcdefgab
子串S2:
abcdex
朴素模式匹配法的原理:
设i,j 分别表示主串S1与子串S2上的第i,j 个元素。i,j 均初始化为11. 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数组的推导 :)
相关文章推荐
- 流程图学习
- 深度学习笔记7 Working with Large Images 卷积特征提取
- 后缀式求值
- Hadoop常见重要命令行操作及命令作用
- 国内外MD5在线解密网站
- Linux asyn-io for socket
- 技术培训----线上 PK 线下?
- 技术培训----线上 PK 线下?
- 数据库操作(2)------------SQLite存储方式
- 并查集-按秩合并
- 同步问题总结
- 新博客开启
- CentOS 安装mysql
- AspNetPager的使用
- windows下XAMPP安装php_memcache扩展
- Tomcat如何添加管理员
- 连接远程LINUX服务器
- 人生故事
- java中的Radom类
- Class.forName().newInstance()和通过new得到对象的区别