我对KMP算法的理解
KMP算法的核心在于失配回溯表——pnext,相比于通过逐个比较来匹配字符串的朴素算法,KMP通过对模式串的分析,可以做到比较指针在主串上不回溯,一直向前。
1. KMP如何实现不回溯?
对于主串 t0 t1....tj,模式串 p在 pi处与 tj 失配,假设 p0~pi-1 存在最长相等前后缀,可以证明将模式串移动至该前缀的后一位,再将其与 tj进行比较,不会漏掉可能的匹配,并且可以大大加速匹配过程。并且这种移动与具体主串无关,仅仅与模式串的失配位置 i 有关,可以通过提前分析模式串,得到失配后的串移动表pnext。
2. 如何得到pnext?
pnext表实质上记录的是模式串中前 i 个元素形成的子串,其最长相等前后缀的大小。即pnext [ i ] 记录着p0到pi-1的子串最长相等前后缀的大小。
具体实现方法就是用模式串自身去逐个比对自身,由前后缀的定义可知,头元素没有相等前后缀,pnext [1]=0。用第0个元素去比对第1个元素,当p0=p1时,pnext [2]=1,接下来比较p1是否等p2;否则pnext [2]=0,接下来继续比较p0是否等p2.......
更一般的,当已知模式串中pnext [ i-1]=k-1,即 p0~pk-2与 pi-k~pi-2求pnext [ i ]。分两种情况:
1)当pi-1=pk-1时,对于i-1的最长相等前后缀,比i-2要多1,那么可以得到pnext [ i ]=k,指针后移,开始求pnext [ i+1];
2)当pi-1!=pk-1时,这时我们需要在 p0~pk-1中继续向前找,在 pi-k~pi-1中继续向后找,寻找新的最长相等前后缀。假设我们寻找到了该串,即前缀为 p0~px-1,后缀为 pi-x~pi-1,那么由于pi-1!=pk-1,而pi-1=px-1。表明px-1!=pk-1,这说明串p0~px-2一定是pk-1的最长相等前后缀串,即pnext [ k ]=x-1。因此当pi-1!=pk-1时,可以直接比对pi-1是否等于ppnext[ k ]!!!此时问题变为:已知模式串中pnext [ i-1]=k-1,求pnext [ i ],其中i-1实际为k,k-1实际值为x-1。若比对成功,则pnext [ i ]=x,指针后移,否则直接比对pi-1是否等于ppnext[ pnext[ k ] ]。问题形成了递归。
将这种递归求值关系与边界条件相结合,我们注意到当p1 !=p0时,pnext [2]=0= -1+1,可以设pnext [0]=-1,则整个求pnext表值过程可以用一个函数统一起来。求值过程从1号位值开始。
def my_pnext(p):
'''模式串的pnext表生成函数'''
m=len(p)
pnext=[-1]*m
i,k=0,-1
while i<m-1:
'''当k=-1时,说明pi != p0 ,没有最大相等前后缀,此时pnext[i]应为0
同样可以将i,k都加1,进行赋值'''
if k==-1 or p[i]==p[k]:
i,k=i+1,k+1
pnext[i]=k
else:
k=pnext[k]
return pnext
相应的KMP函数为:
def my_kmp(t,p,pnext):
'''t是主串,p是模式串,pnext是模式串kmp算法的回溯指针表'''
j,i=0,0
n,m=len(t),len(p)
while j<n and i<m:
if i==-1 or t[j]==p[i]:
j,i=j+1,i+1
else:
i=pnext[i]
if i==m:
return j-i
return -1
我对KMP算法的理解的更多相关文章
- 自己对kmp算法的理解,借由 28. 实现 strStr() 为例
做题思路 or 感想 : 就借由这道题来理解一下kmp算法吧 kmp算法的操作过程我觉得有句话很合适 :KMP 算法永不回退 目标字符串 的指针 i,不走回头路(不会重复扫描 目标字符串),而是借助 ...
- KMP算法 --- 深入理解next数组
在KMP算法中有个数组,叫做前缀数组,也有的叫next数组. 每一个子串有一个固定的next数组,它记录着字符串匹配过程中失配情况下可以向前多跳几个字符. 当然它描述的也是子串的对称程度,程度越高,值 ...
- KMP算法的理解
---恢复内容开始--- 在看数据结构的串的讲解的时候,讲到了KMP算法——一个经典的字符串匹配的算法,具体背景自行百度之,是一个很牛的图灵奖得主和他的学生提出的. 一开始看算法的时候很困惑,但是算法 ...
- 关于《数据结构》课本KMP算法的理解
数据结构课上讲的KMP算法和我在ACM中学习的KMP算法是有区别的,这里我对课本上的KMP算法给出我的一些想法. 原理和之前的KMP是一样的https://www.cnblogs.com/wkfvaw ...
- 关于KMP算法的理解
上次因为haipz组织的比赛中有道题必须用到KMP算法,因此赛后便了解了下它,在仔细拜读了孤~影神牛的文章之后有种茅塞顿开的感觉,再次ORZ. 附上链接http://www.cnblogs.com/y ...
- KMP算法自我理解 和 模板
字符串 abcd abc abcd abc 匹配串 cdabcd 匹配串的 next 0 0 0 0 1 2: 开始匹配 abcd abc abcd abc cd abc d a,d 匹配失 ...
- 第十一章 串 (c3)KMP算法:理解next[]表
- kmp算法初步理解
123456789 abbdaxnds Next 01212 第三位看第二位b,第二位和第三位相同,都是b,所以第三位的next是第二位的next加1,即1+1=2 第四位看第三位b,第四位d与第 ...
- KMP算法中next函数的理解
首先要感谢http://blog.csdn.net/v_july_v/article/details/7041827以及http://blog.chinaunix.net/uid-27164517-i ...
随机推荐
- Java的反射基础技术
今天本人给大家讲解一下Java的反射基础技术,如有不对的或者讲的不好的可以多多提出,我会进行相应的更改,先提前感谢提出意见的各位了!!! 什么是反射? 反射它是根据字节码文件可以反射出类的信息.字段. ...
- 在Centos系统中基于PowerDNS实现master和slave的域名解析服务双备份
在上一篇文章中,阐述了如何在Centos 7系统(其他版本的Centos未尝试)中基于PowerDNS和poweradmin自建域名解析服务器替代DnsPod的过程.但是在一般的DNS服务中,我们需要 ...
- kerberos系列之kerberos安装
最近搞了一下kerberos,准备写一个系列,介绍kerberos的安装,和常用组件kerberos配置,今天进入第一篇:kerberOS安装 具体kerberos是什么东西,大家可以百度查一下,这里 ...
- Callable的Future模式
一.线程实现方式 1.继承Thread类 2.实现Runnable接口 3.线程池 4.Callable 二.无论使用继承Thread类还是实现Runnable接口,还是使用线程池都没有办法解决2个问 ...
- Leetcode_面试题 17.24. 最大子矩阵
最大子矩阵问题,n是200,枚举上下行,O(N)求一下最大子段和. code class Solution { public: vector<int> getMaxMatrix(vecto ...
- Stress-induced changes in the S-palmitoylation and S-nitrosylation of synaptic proteins (解读人:陈凌云)
文献名:Stress-induced changes in the S-palmitoylation and S-nitrosylation of synaptic proteins (压力诱导突触蛋 ...
- python接口调用把执行结果追加到测试用例中
python操作excel的三个工具包如下,注意,只能操作.xls,不能操作.xlsx. xlrd: 对excel进行读相关操作 xlwt: 对excel进行写相关操作 xlutils: 对excel ...
- [React]Hook初探
Hook是什么 Hook是React从16.8开始支持的特性,使用Hook可以在不使用class时使用state Hook支持在不需要修改组件状态的情况下复用逻辑状态,从而解决使用render pro ...
- 《java编程思想》 初始化与清理
1.初始化与清理的重要性: 1.许多C程序的错误都源于程序员忘记初始化变量,特别是使用程序库时,如果不知道如何初始化库的构件更容易出错 2.当使用完一个元素时,这个元素就不会有什么影响了,所以很容易就 ...
- Netty耗时的业务逻辑应该写在哪儿,有什么注意事项?
更多技术分享可关注我 前言 Netty以高性能著称,但是在实际使用中,不可避免会遇到耗时的业务逻辑,那么这些耗时操作应该写在哪儿呢,有什么注意的坑吗?本篇文章将一一总结. Netty线程调度模型回顾 ...