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学习笔记 下载
Feb 10 Python
python 合并文件的具体实例
Aug 08 Python
python字符串连接方式汇总
Aug 21 Python
Python做文本按行去重的实现方法
Oct 19 Python
Python3实现发送QQ邮件功能(文本)
Dec 15 Python
Numpy 将二维图像矩阵转换为一维向量的方法
Jun 05 Python
Python的Lambda函数用法详解
Sep 03 Python
python标识符命名规范原理解析
Jan 10 Python
python中tab键是什么意思
Jun 18 Python
MAC平台基于Python Appium环境搭建过程图解
Aug 13 Python
python基于tkinter实现gif录屏功能
May 19 Python
使用Python+OpenCV进行卡类型及16位卡号数字的OCR功能
Aug 30 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
如何限制访问者的ip(PHPBB的代码)
2006/10/09 PHP
供参考的 php 学习提高路线分享
2011/10/23 PHP
PHP检测字符串是否为UTF8编码的常用方法
2014/11/21 PHP
PHP使用PhpSpreadsheet操作Excel实例详解
2020/03/26 PHP
javascript 动态添加表格行
2006/06/22 Javascript
javascript 表单的友好用户体现
2009/01/07 Javascript
JQUERY实现左侧TIPS滑进滑出效果示例
2013/06/27 Javascript
js判断是否为ie的方法小结
2014/01/13 Javascript
在JavaScript中判断整型的N种方法示例介绍
2014/06/18 Javascript
实例详解jQuery结合GridView控件的使用方法
2016/01/04 Javascript
基于jquery实现动态竖向柱状条特效
2016/02/12 Javascript
javascript基本数据类型及类型检测常用方法小结
2016/12/14 Javascript
jQuery中的100个技巧汇总
2016/12/15 Javascript
JavaScript关联数组用法分析【概念、定义、遍历】
2017/03/15 Javascript
BootStrap Table实现server分页序号连续显示功能(当前页从上一页的结束序号开始)
2017/09/12 Javascript
bootstrap table方法之expandRow-collapseRow展开或关闭当前行数据
2020/08/09 Javascript
vue中实现图片和文件上传的示例代码
2018/03/16 Javascript
angularjs获取到My97DatePicker选中的值方法
2018/10/02 Javascript
微信小程序实现底部导航
2018/11/05 Javascript
vue控制多行文字展开收起的实现示例
2019/10/11 Javascript
vue中音频wavesurfer.js的使用方法
2020/02/20 Vue.js
python微信好友数据分析详解
2018/11/19 Python
Django中更改默认数据库为mysql的方法示例
2018/12/05 Python
详解python3中用HTMLTestRunner.py报ImportError: No module named 'StringIO'如何解决
2019/08/27 Python
Python paramiko模块使用解析(实现ssh)
2019/08/30 Python
python实现按首字母分类查找功能
2019/10/31 Python
解决Python二维数组赋值问题
2019/11/28 Python
Pytorch中Tensor与各种图像格式的相互转化详解
2019/12/26 Python
使用Puppeteer爬取微信文章的实现
2020/02/11 Python
使用python批量修改XML文件中图像的depth值
2020/07/22 Python
财务会计实习报告体会
2013/12/20 职场文书
12岁生日感言
2014/01/21 职场文书
大学生开西餐厅创业计划书
2014/02/01 职场文书
大学生就业推荐表自我评价
2015/03/02 职场文书
放假通知格式
2015/04/14 职场文书
工会经费申请报告
2015/05/15 职场文书