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中函数的参数
Apr 27 Python
Python字典操作详细介绍及字典内建方法分享
Jan 04 Python
Python使用smtp和pop简单收发邮件完整实例
Jan 09 Python
python数据分析数据标准化及离散化详解
Feb 26 Python
Python二叉树定义与遍历方法实例分析
May 25 Python
解决安装tensorflow遇到无法卸载numpy 1.8.0rc1的问题
Jun 13 Python
django 将model转换为字典的方法示例
Oct 16 Python
Python使用pydub库对mp3与wav格式进行互转的方法
Jan 10 Python
Django 拼接两个queryset 或是两个不可以相加的对象实例
Mar 28 Python
Python 实现 T00ls 自动签到脚本代码(邮件+钉钉通知)
Jul 06 Python
Python如何实现远程方法调用
Aug 07 Python
讲解Python实例练习逆序输出字符串
May 06 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 include加载文件两种方式效率比较
2010/08/08 PHP
解析php入库和出库
2013/06/25 PHP
详谈PHP面向对象中常用的关键字和魔术方法
2017/02/04 PHP
在云虚拟主机部署thinkphp5项目的步骤详解
2017/12/21 PHP
laravel 数据验证规则详解
2019/10/23 PHP
PHP的垃圾回收机制代码实例讲解
2021/02/27 PHP
JS实现div内部的文字或图片自动循环滚动代码
2013/04/19 Javascript
基于JavaScript 下namespace 功能的简单分析
2013/07/05 Javascript
jQuery - css() 方法示例详解
2014/01/16 Javascript
用原生js做个简单的滑动效果的回到顶部
2014/10/15 Javascript
jQuery+HTML5实现手机摇一摇换衣特效
2015/06/05 Javascript
JS实现完全语义化的网页选项卡效果代码
2015/09/15 Javascript
Javascript简写条件语句(推荐)
2016/06/12 Javascript
第八篇Bootstrap下拉菜单实例代码
2016/06/21 Javascript
解析javascript图片懒加载与预加载的分析总结
2016/10/27 Javascript
JS中数组重排序方法
2016/11/11 Javascript
Bootstrap与Angularjs的模态框实例代码
2017/08/03 Javascript
一起深入理解js中的事件对象
2021/02/06 Javascript
[04:16]DOTA2英雄梦之声_第09期_斧王
2014/06/21 DOTA
Hadoop中的Python框架的使用指南
2015/04/22 Python
python保存网页图片到本地的方法
2018/07/24 Python
django中使用事务及接入支付宝支付功能
2019/09/15 Python
python 画3维轨迹图并进行比较的实例
2019/12/06 Python
如何基于Python实现自动扫雷
2020/01/06 Python
Django后台管理系统的图文使用教学
2020/01/20 Python
Jupyter Notebook远程登录及密码设置操作
2020/04/10 Python
Django model.py表单设置默认值允许为空的操作
2020/05/19 Python
python使用hdfs3模块对hdfs进行操作详解
2020/06/06 Python
域名注册、建站工具、网页主机、SSL证书:Dynadot
2017/01/06 全球购物
美国潜水装备、水肺潜水和浮潜设备商店:Leisure Pro
2018/08/08 全球购物
参观监狱心得体会
2014/01/02 职场文书
大学英语演讲稿范文
2014/04/24 职场文书
大学学生会竞选演讲稿
2014/04/25 职场文书
消防安全宣传口号
2014/06/10 职场文书
新闻编辑专业自荐信
2014/07/02 职场文书
小学见习报告
2014/10/31 职场文书