说起kmp就要从字符串的匹配说起,下面我们谈谈字符串的匹配

给定一个原字符串:bababababababababb,再给定一个模式串:bababb,求模式串是否在源字符串中出现

最简单的方法就是遍历源字符串,再遍历模式串,依次进行对比。当遇到不匹配的字符时源字符串和模式串返回下一个位置重新开始匹配,复杂度为n^2。

普通方法其实有可以优化的地方,假设源为字符串Q[1...n],模式串M[1...m]。

按照普通方法Q和M从i,j处进行匹配,当在k位置发生不匹配时,Q返回i+1位置,M返回开始0处重新匹配。

babab|ababababababb  -- i = 5

babab|b    -- j = 5 此处不匹配

b|ababababababababb -- i = 2

bababb  -- j = 0 此处不匹配

bababababababababb

bababb  此处匹配完成

我们从这里思考一下,上式当开始匹配到i=5,j=5时发生了不匹配,下一步就是i返回到i=1,j=0重新匹配,其实i不用返回到1,试想一下Q[1..5]和M[1...5]是匹配的

那么Q[2...5]和M[1...5]是不匹配的,除非Q[1] = Q[2] Q[2] = Q[3] .... 同理Q[3...5]和M[1...5]匹配Q[1] = Q[2] = Q[3] ...,这么说来其实i也不用回溯了,这样j返回到正确的位置就可以继续匹配,那j这个位置怎么确定呢?

j位置无非就是使得Q[i-j, i] = M[1..j] 成立的位置,然后从这个位置继续往下匹配,中间略过的一定是不匹配的,不信自己可以证明一下。再想想刚才说的假设Q[1..i]和M[1...i]是匹配的即 Q[1...i] = M[1...i] 取局部i-j使得Q[i-j...i] = M[i-j...i] 把 Q[i-j, i] = M[1..j]带入得到 M[i-j...i] = M[1...j] 就是说要找的一个位置j使得开始j个长度的字符串等于结尾j长度的字符串。为了不漏掉匹配字符串的长度尽可能长,我们用k表示可匹配的字符串的长度则上述描述变为如下形式

找到 max(k) s.t. M[i-k...i] = M[1...k] 突然发现简单了,可以问题又来了怎么找到这样的k呢?回答是枚举呗k=1,k=2,k=3...找最长的成立的那个代码如下

 def NEXT(pattern):
Next = [0] * (len(pattern)+1)
Next[0] = -1
pattern_len = len(pattern) for i in range(pattern_len+1):
k = 0
for j in range(i):
if pattern[0:j] == pattern[i-j:i]:
k = j
Next[i] = k return Next

好像又回到了出发点还是n^2的复杂度,不行不能这样堕落啊再想想。用Next表示当前模式串改回溯的位置初始化Next[0] = -1

当M[i-k...i] = M[1...k]已经成立,那么Next[i] = k ,当M[k+1] = M[i+1] 时M[i-k...i+1] = M[1...k+1] 因此M[k+1] = M[i+1] 时Next[i+1] = k + 1

当M[i-k...i] != M[1...k]时,k一定是要缩小到,怎么缩小呢?是不是要缩到某个k1的值 s.t. M[i-k1...i] = M[1...k1],如果还不匹配怎么办,继续缩小啊,是不是发现规律了对k = Next[k]不停向前缩小直到找到某个k2的值s.t. M[i-k2...i] = M[1...k2] 然后 Next[i+1] = k2。以上就是Next的递归求解复杂度只要O(m)啊,直接秒杀n^2

 def NEXT(pattern):
Next = [0] * (len(pattern)+1)
Next[0] = -1
pattern_len = len(pattern) for i in range(pattern_len):
j = i
while j > 0:
if pattern[Next[j]] == pattern[i]:
Next[i+1] = Next[j]+1
break
else:
j = Next[j] return Next

Next的使用我就不讲解了,和普通字符串的回溯一样,只不过每次回溯到值都是Next里面的值,将复杂度降低到了O(m+n),代码全部明天贴

KMP学习之旅的更多相关文章

  1. WCF学习之旅—第三个示例之四(三十)

           上接WCF学习之旅—第三个示例之一(二十七)               WCF学习之旅—第三个示例之二(二十八)              WCF学习之旅—第三个示例之三(二十九)   ...

  2. Hadoop学习之旅二:HDFS

    本文基于Hadoop1.X 概述 分布式文件系统主要用来解决如下几个问题: 读写大文件 加速运算 对于某些体积巨大的文件,比如其大小超过了计算机文件系统所能存放的最大限制或者是其大小甚至超过了计算机整 ...

  3. WCF学习之旅—第三个示例之二(二十八)

    上接WCF学习之旅—第三个示例之一(二十七) 五.在项目BookMgr.Model创建实体类数据 第一步,安装Entity Framework 1)  使用NuGet下载最新版的Entity Fram ...

  4. WCF学习之旅—第三个示例之三(二十九)

    上接WCF学习之旅—第三个示例之一(二十七) WCF学习之旅—第三个示例之二(二十八) 在上一篇文章中我们创建了实体对象与接口协定,在这一篇文章中我们来学习如何创建WCF的服务端代码.具体步骤见下面. ...

  5. WCF学习之旅—WCF服务部署到IIS7.5(九)

    上接   WCF学习之旅—WCF寄宿前的准备(八) 四.WCF服务部署到IIS7.5 我们把WCF寄宿在IIS之上,在IIS中宿主一个服务的主要优点是在发生客户端请求时宿主进程会被自动启动,并且你可以 ...

  6. WCF学习之旅—WCF服务部署到应用程序(十)

    上接  WCF学习之旅—WCF寄宿前的准备(八) WCF学习之旅—WCF服务部署到IIS7.5(九) 五.控制台应用程序宿主 (1) 在解决方案下新建控制台输出项目 ConsoleHosting.如下 ...

  7. WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一)

    上接    WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) 七 WCF服务的Windows 服务程序寄宿 这种方式的服务寄宿,和IIS一样有一个一样 ...

  8. WCF学习之旅—WCF服务的WAS寄宿(十二)

    上接    WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一) 八.WAS宿主 IIS ...

  9. WCF学习之旅—WCF服务的批量寄宿(十三)

    上接    WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一) WCF学习之旅—WCF ...

随机推荐

  1. Android 更改 Toast 的默认位置

    Android中Toast的默认位置在屏幕靠近底部的位置,这个默认位置有时候并不合适.比如页面上内容较少时,内容一般集中在屏幕上半部分,用户的注意力也集中在屏幕上半部分,默认位置的Toast用户可能没 ...

  2. (转)NIO与AIO,同步/异步,阻塞/非阻塞

    原文地址: http://www.cnblogs.com/enjoy-ourselves/p/3793771.html 1.flip(),compact(),与clear()的使用 flip()内部实 ...

  3. split和join的用法

    第一点:split 直接举例子,比较直观, >>> f = 'www.baidu.com.cn' >>> f.split()['www.baidu.com.cn'] ...

  4. Less:优雅的写CSS代码

    css是不能够定义变量的,也不能嵌套.它没有编程语言的特性.在项目开发中,常常发现有很多css代码是相同的,但我们通常都是复制然后粘贴. 举个例子:假设h5应用里主题色是#FF3A6D,可能用于文字或 ...

  5. common-pool2 学习:thrift连接池的另一种实现

    对象池是一种很实用的技术,经典的例子就是数据库连接池.去年曾经从零开始写过一个thrift客户端连接池.如果不想重造轮子,可以直接在apache开源项目commons-pool的基础上开发. 步骤: ...

  6. [LeetCode] Isomorphic Strings 同构字符串

    Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if the chara ...

  7. ImportError: cannot import name '_imagingtk'

    问题描述 使用tkinter画pillow生成的图片时,在tkinter中抛出此异常. 解决方案 pip install -I --no-cache-dir Pillow 更新pillow 重启解决一 ...

  8. 【ios开发】使用自定义的TableViewCell

    当系统自带的cell无法满足我们的要求的时候,我们就可以自定义自己的cell. 先看看效果,这个效果有点重复造轮子的感觉,因为UITableView已经实现了这种布局. 打造自己的cell只需简单的3 ...

  9. vim修改文字编码

    在Vim中查看文件编码 :set fileencoding 即可显示文件编码格式.如果你只是想查看其它编码格式的文件或者想解决 用Vim查看文件乱码的问题,那么在~/.vimrc 文件中添加以下内容: ...

  10. SpringMVC注解汇总(一)-定义

    本文根据开涛哥学习SpringMVC汇总而成,方便更好查阅! 网址:http://jinnianshilongnian.iteye.com/blog/1752171 注解式控制器简介 @Control ...