KMP算法精解及其Python版的代码示例


Posted in Python onJune 01, 2016

KMP算法是经典的字符串匹配算法,解决从字符串S,查找模式字符串M的问题。算法名称来源于发明者Knuth,Morris,Pratt。
假定从字符串S中查找M,S的长度ls,M的长度lm,且(ls > lm)。

朴素的字符串查找方法
从字符串S的第一个字符开始与M进行比较,如果匹配失败。从下一字符开始,重新比较。指导第 (ls - lm) 个字符。
这种方法容易想到并且容易理解,效率不高。
问题在于每次匹配失败后,移动的步伐固定为 1,其实步子可以迈得再大一些。

KMP的字符串查找方法
假定在模式串的连续字串M[0, i] 且 i < lm,已经成功匹配字符串S。但是不巧第 i+1 个字符失败了,怎么办?移动一个字符,重头再来?当然不好,那就是朴素路线了。我们能否从跌倒的地方继续走呢?
既然字串M[0 - i]已经匹配成功,那就从这个子串上做文章。举个栗子     

S序号 j j + 1  j + 2 j + 3 j + 4 j + 5  j+6 j + 7 。。。
S串 a b c a b c d e 。。。
M串 a b c a b d
M序号 0 1 2 3 4 5

此时匹配失败在M串的第5个字符,前4个字符已经匹配成功。
如果从跌倒的地方出发,则需要存在M[0, 4]的子串M[0, k] == S[j+4-k , j+4]。
由于M[0, 4] == S[j ,  j+4] 则有 字串S[j+4-k, j+4] == M[4-k, 4]。综上有M[0, k] == M[4-k, 4]
如果这样的k不存在,那就老老实实的朴素了。
从上面的表格可以直观的看出,下一次匹配只要把M串移动到 j + 3 位置,从 j+5 开始匹配就可以。很容易看出来 在已经匹配成功的字串M[0 , 4]中有最长的子串 (M[0 , 1] == M[3 , 4]),这个就是问题的关键。
因此KMP的核心部分就是计算模式串的各个子串的 k。

实例
首先我们来看一下字符串的朴素匹配.
可以想象成把文本串s固定住,模式串p从s最左边开始对齐,如果对齐的部分完全一样,则匹配成功,失败则将模式串p整体往右移1位,继续检查对齐部分,如此反复.

#朴素匹配 
def naive_match(s, p): 
 m = len(s); n = len(p) 
 for i in range(m-n+1):#起始指针i 
  if s[i:i+n] == p: 
   return True 
 return False

关于kmp算法,讲的最好的当属阮一峰的<字符串匹配的KMP算法>.一路读下来,豁然开朗.
其实就是,对模式串p进行预处理,得到前后缀的部分匹配表,使得我们可以借助已知信息,算出可以右移多少位.即 kmp = 朴素匹配 + 移动多位.
更多细节请看阮一峰的文章,这里就不展开了.
下面给出python的代码实现.

#KMP 
def kmp_match(s, p): 
 m = len(s); n = len(p) 
 cur = 0#起始指针cur 
 table = partial_table(p) 
 while cur<=m-n: 
  for i in range(n): 
   if s[i+cur]!=p[i]: 
    cur += max(i - table[i-1], 1)#有了部分匹配表,我们不只是单纯的1位1位往右移,可以一次移动多位 
    break 
  else: 
   return True 
 return False 
 
#部分匹配表 
def partial_table(p): 
 '''''partial_table("ABCDABD") -> [0, 0, 0, 0, 1, 2, 0]''' 
 prefix = set() 
 postfix = set() 
 ret = [0] 
 for i in range(1,len(p)): 
  prefix.add(p[:i]) 
  postfix = {p[j:i+1] for j in range(1,i+1)} 
  ret.append(len((prefix&postfix or {''}).pop())) 
 return ret 
 
print naive_match("BBC ABCDAB ABCDABCDABDE", "ABCDABD") 
print partial_table("ABCDABD") 
print kmp_match("BBC ABCDAB ABCDABCDABDE", "ABCDABD")

Python 相关文章推荐
Python random模块(获取随机数)常用方法和使用例子
May 13 Python
Python解析excel文件存入sqlite数据库的方法
Nov 15 Python
matplotlib简介,安装和简单实例代码
Dec 26 Python
浅谈利用numpy对矩阵进行归一化处理的方法
Jul 11 Python
django+xadmin+djcelery实现后台管理定时任务
Aug 14 Python
PyQt5实现类似别踩白块游戏
Jan 24 Python
python移位运算的实现
Jul 15 Python
Django项目中使用JWT的实现代码
Nov 04 Python
Python测试Kafka集群(pykafka)实例
Dec 23 Python
python使用numpy实现直方图反向投影示例
Jan 17 Python
解决Python中报错TypeError: must be str, not bytes问题
Apr 07 Python
python文件编写好后如何实践
Jul 07 Python
Python缩进和冒号详解
Jun 01 #Python
Python注释详解
Jun 01 #Python
深入理解python try异常处理机制
Jun 01 #Python
python学习 流程控制语句详解
Jun 01 #Python
python+Django+apache的配置方法详解
Jun 01 #Python
python中函数默认值使用注意点详解
Jun 01 #Python
Python中基础的socket编程实战攻略
Jun 01 #Python
You might like
基于文本的留言簿
2006/10/09 PHP
在yii中新增一个用户验证的方法详解
2013/06/20 PHP
Laravel 5.2 文档 数据库 ―― 起步介绍
2019/10/21 PHP
XP折叠菜单&amp;仿QQ2006菜单
2006/12/16 Javascript
jQuery 各种浏览器下获得日期区别
2008/12/22 Javascript
最短的javascript:地址栏载入脚本代码
2011/10/13 Javascript
jQuery中判断一个元素是否为另一个元素的子元素(或者其本身)
2012/03/21 Javascript
表单类各种类型(文本框)失去焦点效果jquery代码
2013/04/26 Javascript
JS实现图片无间断滚动代码汇总
2014/07/30 Javascript
如何用javascript计算文本框还能输入多少个字符
2015/07/29 Javascript
JS实现日期时间动态显示的方法
2015/12/07 Javascript
基于jquery编写的放大镜插件
2016/03/23 Javascript
AngularJS国际化详解及示例代码
2016/08/18 Javascript
AngularJS+bootstrap实现动态选择商品功能示例
2017/05/17 Javascript
微信小程序 支付功能(前端)的实现
2017/05/24 Javascript
详解webpack引入第三方库的方式以及注意事项
2019/01/15 Javascript
JavaScript实现图片轮播特效
2019/10/23 Javascript
JS使用正则表达式实现常用的表单验证功能分析
2020/04/30 Javascript
Python线程下使用锁的技巧分享
2018/09/13 Python
用python生成1000个txt文件的方法
2018/10/25 Python
详解用python自制微信机器人,定时发送天气预报
2019/03/25 Python
Python closure闭包解释及其注意点详解
2019/08/28 Python
浅谈keras中的目标函数和优化函数MSE用法
2020/06/10 Python
python 读取.nii格式图像实例
2020/07/01 Python
python基于pygame实现飞机大作战小游戏
2020/11/19 Python
CSS3实现水平居中、垂直居中、水平垂直居中的实例代码
2020/02/27 HTML / CSS
mui几种页面跳转方式对比总结概括
2017/08/18 HTML / CSS
马歇尔耳机官网:Marshall Headphones
2020/02/04 全球购物
枚举与#define宏的区别
2014/04/30 面试题
表扬信格式
2014/01/12 职场文书
教师考核材料
2014/05/21 职场文书
建筑专业毕业生自荐信
2014/05/25 职场文书
2014年计生工作总结
2014/11/21 职场文书
Mysql MVCC机制原理详解
2021/04/20 MySQL
springcloud整合seata
2022/05/20 Java/Android
TypeScript 内置高级类型编程示例
2022/09/23 Javascript