说起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. Ajax语法浅析

    Ajax是目前很普遍的一门技术,也是很值得探讨和研究的一门技术.本文将针对Ajax的发展过程并结合其在不同库框架中的使用方式来和大家分享下Ajax的那些新老语法. Ajax简介 Ajax全称为“Asy ...

  2. JQuery 滚动轮播

    css: *{margin: 0;padding: 0;}body{font-size: 12px;line-height: 24px;text-algin: center; }a{color: #f ...

  3. Lambert(朗伯)光照模型 和Half Lambert的区别

    Lambert-它不包括任何任何镜面属性,对粗糙物体来说,这项属性是非常有用的,它不会反射出周围的环境.Lambert材质可以是透明的,在光线追踪渲染中发生折射,但是如果没有镜面属性,该类型就不会发生 ...

  4. [LeetCode] Valid Palindrome 验证回文字符串

    Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignori ...

  5. const 引起的BUG

    今天白天出现了碰见了一个问题,隐藏得比较深,这里记录一下. 初衷很简单,就是要更改改一个数据库的链接名,这个链接名是放在数据层public const string connDB="conn ...

  6. js自定义验证码

    分享一个js自定义的验证码 window.onload = function () {     var code;     $('.changePassword').click(function () ...

  7. BAS/BRAS/RADIUS简介

    标签: java radius协议   linux radius认证服务器   转自: http://blog.csdn.net/sun93732/article/details/5999274 由R ...

  8. 一个简单oop的changeTab

    好多地方都会用到这样一个效果“点击tab切换内容页”,根据自己的想法实现了一下,写了个简单的插件.以前写代码都是标准的函数式编程,现在觉得面向对象编程看起来比较爽,并且更容易维护,于是就用oop的思想 ...

  9. 求n!最后一位非零数

    引子:求n!末尾0的个数 n!末尾的0来源只有2,5两个质数相乘.所以只需要考察n!中包含多少个2和多少个5.然后取其较小值即为所求.即ans=min(cnt(2),cnt(5)).而转念一想,cnt ...

  10. shell及脚本3——正则表达式

    一.正则表达式 1.1. 什么是正则表达式 正则表达式是处理字符串的方法,以行为单位,通过一些特殊符号的辅助,让用户可以轻易进行查找.删除.替换某特定字符串的操作. 1.2. 正则表达式与通配符的区别 ...