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抽象基类用法实例分析
Jun 04 Python
Python函数式编程指南(一):函数式编程概述
Jun 24 Python
在类Unix系统上开始Python3编程入门
Aug 20 Python
Python基于list的append和pop方法实现堆栈与队列功能示例
Jul 24 Python
Django之模型层多表操作的实现
Jan 08 Python
对Python中class和instance以及self的用法详解
Jun 26 Python
python画图——实现在图上标注上具体数值的方法
Jul 08 Python
Python缓存技术实现过程详解
Sep 25 Python
python区分不同数据类型的方法
Oct 14 Python
pytorch中的自定义数据处理详解
Jan 06 Python
Python3监控疫情的完整代码
Feb 20 Python
python图像处理 PIL Image操作实例
Apr 09 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
十天学会php之第一天
2006/10/09 PHP
基于pear auth实现登录验证
2010/02/26 PHP
php批量删除操作(数据访问)
2017/05/23 PHP
js 禁用浏览器的后退功能的简单方法
2008/12/10 Javascript
检测是否已安装 .NET Framework 3.5的js脚本
2009/02/14 Javascript
jquery下checked取值问题的解决方法
2012/08/09 Javascript
JavaScript模板入门介绍
2012/09/26 Javascript
JQuery弹出炫丽对话框的同时让背景变灰色
2014/05/22 Javascript
封装属于自己的JS组件
2016/01/27 Javascript
解决node.js安装包失败的几种方法
2016/09/02 Javascript
D3.js实现直方图的方法详解
2016/09/25 Javascript
Bootstrap3下拉菜单的实现
2017/02/22 Javascript
js获取浏览器的各种属性
2017/04/27 Javascript
JS库之Highlight.js的用法详解
2017/09/13 Javascript
bootstrap Table服务端处理分页(后台是.net)
2017/10/19 Javascript
JavaScript实现职责链模式概述
2018/01/25 Javascript
vue中利用simplemde实现markdown编辑器(增加图片上传功能)
2019/04/29 Javascript
js实现鼠标拖拽div左右滑动
2020/01/15 Javascript
Python中的MongoDB基本操作:连接、查询实例
2015/02/13 Python
python使用json序列化datetime类型实例解析
2018/02/11 Python
python读取txt文件,去掉空格计算每行长度的方法
2018/12/20 Python
画pytorch模型图,以及参数计算的方法
2019/08/17 Python
解决安装新版PyQt5、PyQT5-tool后打不开并Designer.exe提示no Qt platform plugin的问题
2020/04/24 Python
Python文件名匹配与文件复制的实现
2020/12/11 Python
卡塔尔航空官方网站:Qatar Airways
2017/02/08 全球购物
WebSphere 应用服务器都支持哪些认证
2013/12/26 面试题
大学毕业的自我鉴定
2013/10/08 职场文书
师范教师大学生职业生涯规划范文
2014/01/05 职场文书
村委会主任先进事迹
2014/01/15 职场文书
婚前协议书怎么写
2014/04/15 职场文书
小学校长先进事迹材料
2014/05/13 职场文书
实训报告范文大全
2014/11/04 职场文书
pandas中DataFrame重置索引的几种方法
2021/05/24 Python
Django路由层如何获取正确的url
2021/07/15 Python
MySQL 原理与优化之Limit 查询优化
2022/08/14 MySQL
spring boot实现文件上传
2022/08/14 Java/Android