KMP算法-Python版

传统法:

从左到右一个个匹配,如果这个过程中有某个字符不匹配,就跳回去,将模式串向右移动一位。这有什么难的?

我们可以这样初始化:

之后我们只需要比较i指针指向的字符和j指针指向的字符是否一致。如果一致就都向后移动,如果不一致,如下图:

A和E不相等,那就把i指针移回第1位(假设下标从0开始),j移动到模式串的第0位,然后又重新开始这个步骤:

因为主串匹配失败的位置前面除了第一个A之外再也没有A,我们为什么能知道主串前面只有一个A?因为我们已经知道前面三个字符都是匹配的!(这很重要)。移动过去肯定也是不匹配的!有一个想法,i可以不动,我们只需要移动j即可,如下图:

KMP算法。其思想:“利用已知部分匹配这个有效信息,保持i指针不回溯,通过修改j指针,让模式串尽量地移动到有效的位置。”

当匹配失败时,j要移动的下一个位置k。存在着这样的性质:最前面的k个字符和j之前的最后k个字符是一样的

如果用数学公式来表示:P[0 ~ k-1] == P[j-k ~ j-1]

当T[i] != P[j]时

有T[i-j ~ i-1] == P[0 ~ j-1]

由P[0 ~ k-1] == P[j-k ~ j-1]

必然:T[i-k ~ i-1] == P[0 ~ k-1]

next[j]的值(也就是k)表示,当P[j] != T[i]时,j指针的下一步移动位置

先来看第一个:当j为0时,如果这时候不匹配,

像上图这种情况,j已经在最左边了,不可能再移动了,这时候要应该是i指针后移。所以在代码中才会有next[0] = -1;这个初始化。

当j为1

显然,j指针一定是后移到0位置的。因为它前面也就只有这一个位置

下面这个是最重要的,请看如下图:

 

请仔细对比这两个图。

我们发现一个规律:

当P[k] == P[j]时,

有next[j+1] == next[j] + 1

其实这个是可以证明的:

因为在P[j]之前已经有P[0 ~ k-1] == p[j-k ~ j-1]。(next[j] == k)

这时候现有P[k] == P[j],我们是不是可以得到P[0 ~ k-1] + P[k] == p[j-k ~ j-1] + P[j]。

即:P[0 ~ k] == P[j-k ~ j],即next[j+1] == k + 1 == next[j] + 1。

这里的公式不是很好懂,还是看图会容易理解些。

那如果P[k] != P[j]呢?比如下图所示:

像这种情况,如果你从代码上看应该是这一句:k = next[k];如下图:

k = next[k],像上边的例子,我们已经不可能找到[ A,B,A,B ]这个最长的后缀串了,但我们还是可能找到[ A,B ]、[ B ]这样的前缀串的。所以这个过程像不像在定位[ A,B,A,C ]这个串,当C和主串不一样了(也就是k位置不一样了),把指针移动到next[k]。


  1. def KMP(A,P):#O(M+N)
  2. i = 0#主串的位置
  3. j = 0#模式串的位置
  4. nextArray = getNext(P)
  5. while i < len(A) and j < len(P):
  6. if j == -1 or A[i] == P[j]:
  7. i += 1
  8. j += 1
  9. else:#i不回溯
  10. j = nextArray[j]#j回到指定位置
  11. if j == len(P):
  12. return i-j
  13. else:
  14. return -1
  15. def getNext(P):
  16. nextArray = [0 for i in range(len(P))]
  17. nextArray[0] = -1
  18. j = 0
  19. k = -1
  20. while j < len(P)-1:
  21. if k == -1 or P[j] == P[k]:
  22. j += 1
  23. k += 1
  24. if P[j] == P[k]:#两个字符相等跳过
  25. nextArray[j] = nextArray[k]
  26. else:
  27. nextArray[j] = k
  28. else:
  29. k = nextArray[k]
  30. return nextArray
  31. if __name__ == '__main__':
  32. A = "ABACBCDHI"
  33. P = "CD"
  34. res = KMP(A,P)
  35. print(res)

				<script>
(function(){
function setArticleH(btnReadmore,posi){
var winH = $(window).height();
var articleBox = $("div.article_content");
var artH = articleBox.height();
if(artH > winH*posi){
articleBox.css({
'height':winH*posi+'px',
'overflow':'hidden'
})
btnReadmore.click(function(){
articleBox.removeAttr("style");
$(this).parent().remove();
})
}else{
btnReadmore.parent().remove();
}
}
var btnReadmore = $("#btn-readmore");
if(btnReadmore.length>0){
if(currentUserName){
setArticleH(btnReadmore,3);
}else{
setArticleH(btnReadmore,1.2);
}
}
})()
</script>
</article>

KMP算法-Python版的更多相关文章

  1. kmp算法python实现

    kmp算法python实现 kmp算法 kmp算法用于字符串的模式匹配,也就是找到模式字符串在目标字符串的第一次出现的位置比如abababc那么bab在其位置1处,bc在其位置5处我们首先想到的最简单 ...

  2. 北京大学公开课《数据结构与算法Python版》

    之前我分享过一个数据结构与算法的课程,很多小伙伴私信我问有没有Python版. 看了一些公开课后,今天特向大家推荐北京大学的这门课程:<数据结构与算法Python版>. 课程概述 很多同学 ...

  3. 【数据结构与算法Python版学习笔记】引言

    学习来源 北京大学-数据结构与算法Python版 目标 了解计算机科学.程序设计和问题解决的基本概念 计算机科学是对问题本身.问题的解决.以及问题求解过程中得出的解决方案的研究.面对一 个特定问题,计 ...

  4. BF算法和KMP算法 python实现

    BF算法 def Index(s1,s2,pos = 0): """ BF算法 """ i = pos j = 0 while(i < ...

  5. 字符串匹配的KMP算法——Python实现

    #! /usr/bin/python # coding=utf-8 """ 基于这篇文章的python实现 http://blog.sae.sina.com.cn/arc ...

  6. 排序算法-python版

    总结了一下常见集中排序的算法 归并排序 归并排序也称合并排序,是分治法的典型应用.分治思想是将每个问题分解成个个小问题,将每个小问题解决,然后合并. 具体的归并排序就是,将一组无序数按n/2递归分解成 ...

  7. 学习笔记:[算法分析]数据结构与算法Python版[基本的数据结构-上]

    线性结构Linear Structure ❖线性结构是一种有序数据项的集合,其中 每个数据项都有唯一的前驱和后继 除了第一个没有前驱,最后一个没有后继 新的数据项加入到数据集中时,只会加入到原有 某个 ...

  8. 【数据结构与算法Python版学习笔记】算法分析

    什么是算法分析 算法是问题解决的通用的分步的指令的聚合 算法分析主要就是从计算资源的消耗的角度来评判和比较算法. 计算资源指标 存储空间或内存 执行时间 影响算法运行时间的其他因素 分为最好.最差和平 ...

  9. 【数据结构与算法Python版学习笔记】查找与排序——散列、散列函数、区块链

    散列 Hasing 前言 如果数据项之间是按照大小排好序的话,就可以利用二分查找来降低算法复杂度. 现在我们进一步来构造一个新的数据结构, 能使得查找算法的复杂度降到O(1), 这种概念称为" ...

随机推荐

  1. Spring boot 集成 Swagger

    添加依赖包 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swa ...

  2. 尝试将 SCRIPT ompbox\private\ompmex 作为函数执行

    1.安装VS2010 2.配置ombox 在ombox路径下 mex -setup C++ 然后 make

  3. Android笔记(预安装APK)

    一般一个安卓的产品在出厂时,会预安装许多APK,关于这些APP,主要分为下面这几类 1.系统级别APK 这一类应用一般是:电话/设置或者厂家自己特定的应用. 2.系统预安装APK 因为商业原因,产品出 ...

  4. java对象传递小解析

    先上代码: import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder ...

  5. MVAPICH

    from:https://developer.nvidia.com/mvapich MVAPICH2 is an open source implementation of Message Passi ...

  6. react(二):组件的通信

    对于组件来说,通信无非两种,父子组件通信,和非父子组件通信 一.父子父子组件通信 1.父组件给子组件传值 对于父组件来说,props是他们之间的媒介 class Parent extends Comp ...

  7. C# grid控件用数据库分页后台怎么写?

    C#grid控件使用数据库分页的写法如下: mySystem.GetDataa(gridName.PageIndex *gridName.PageSize + 1, (gridName.PageInd ...

  8. linux下 利用 rz 命令上传文件

    1. 如何安装? 1)编译安装  root 账号登陆后,依次执行以下命令: # cd /tmp # wget http://www.ohse.de/uwe/releases/lrzsz-0.12.20 ...

  9. Percona-Tookit工具包之pt-stalk

      Preface       We have a lot of methods to diagnose problems in our system such as strace,pstack,gs ...

  10. spring cloud 学习之服务消费者(Feign)

    一.Feign简介 Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单.使用Feign,只需要创建一个接口并注解.它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注 ...