详解又详解KMP中的next和nextval的算法

一、定义

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。


二、图解原理

以下借用http://www.cnblogs.com/c-cloud/p/3224788.html的部分内容 
这种算法不太容易理解,网上有很多解释,但读起来都很费劲。直到读到这篇文章,我才真正理解这种算法。下面,我用自己的语言,试图写一篇比较好懂的KMP算法解释。

1.

首先,字符串”BBC ABCDAB ABCDABCDABDE”的第一个字符与搜索词”ABCDABD”的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。

2.

因为B与A不匹配,搜索词再往后移。

3.

就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。

4.

接着比较字符串和搜索词的下一个字符,还是相同。

5.

直到字符串有一个字符,与搜索词对应的字符不相同为止。 
当空格与D不匹配时,你其实知道前面六个字符是”ABCDAB”。KMP算法的想法是,设法利用这个已知信息,不要把”搜索位置”移回已经比较过的位置,继续把它向后移,这样就提高了效率。

6.

因为空格与C不匹配,搜索词还要继续往后移。

7.

逐位比较,直到发现C与D不匹配。于是,继续将搜索词向后移动。

8.

逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。


三、详解

标号(j) 1 2 3 4 5 6 7
模式串(P) A B C D A B D

1、KMP算法的核心思想

——就是回溯到存在”对称“的地方。

  • 注意,这里的“对称”不是指ABCCBA,而是指例如”ABCABC”中队前队尾都分别有1个”ABC”,又例如”ABCCCCCAB”中队前队尾都分别有一个”AB”。

2、看图说话

从第2部分图中可以分析得出,当扫描到模式串中某一位发现不匹配,总是回溯到在这一位之前的部分模式串存在重复的地方

  • 例如2.5中找不到字母D(标号4),D之前串为”ABCDAB”,存在队前队尾重复”AB”(2个字符),因此退回到队首的“AB”后一位C(标号3)。
  • 例如2.6中找不到字母C(标号3),C之前串为”AB”,不存在重复的(0个字符),因此退回到队首最前面(标号1)。

所以,next(j)就是当模式串第j位不匹配时即将要退回到的字母标号

  • 以上例子也可以看出,如果有2个字符重复,就退到第3位,如果有0个字符重复,就退到第1位。显然这是一个+1的关系。

3、next计算过程

不管第一位和第二位是什么,第一位next(1)=0,第二位next(2)=1,这是固定的。

当j=3时,P(j)=C,C之前有”AB”,不存在重复(0位),所以next(3)=0+1=1; 
当j=4时,P(j)=D,C之前有”ABC”,不存在重复(0位),所以next(4)=0+1=1; 
当j=5时,P(j)=A,C之前有”ABCD”,不存在重复(0位),所以next(5)=0+1=1; 
当j=6时,P(j)=B,C之前有”ABCDA”,存在重复”A”(1位),所以next(6)=1+1=2; 
当j=7时,P(j)=D,C之前有”ABCDAB”,存在重复”AB”(2位),所以next(7)=2+1=3;

4、nextval=对next的优化

观察第5位”A”,当它不匹配时,按照next行回溯到标号1也为字母A,这时再匹配A是徒劳的,因为已知A不匹配,所以就继续退回到标号1字母A的next(1)=0。为了直接点进行优化,就有了nextval行:

  • 只看前面有重复字母的几位就可以。

j=5,P(5)=A,next(5)=1,P(1)=A=P(5),所以nextval(5)=next(1)=0; 
j=6,P(6)=B,next(6)=2,P(2)=B=P(6),所以nextval(6)=next(2)=1; 
j=7,P(7)=D,next(7)=3,P(3)=C!=P(7),所以nextval(7)=next(7)=3;


结果:

标号(j) 1 2 3 4 5 6 7
模式串(P) A B C D A B D
next 0 1 1 1 1 2 3
nextval 0 1 1 1 0 1 3

详解完毕,希望大家喜欢。

 

原文 https://blog.csdn.net/nanami809/article/details/49367159

全部评论

相关推荐

07-15 14:14
门头沟学院 Java
7.10投递7.15感谢信
投递地平线等公司7个岗位
点赞 评论 收藏
分享
Twilight_m...:表格简历有点难绷。说说个人看法: 1.个人基本情况里好多无意义信息,什么婚姻状况、健康状况、兴趣爱好、户口所在地、身份证号码、邮政编码,不知道的以为你填什么申请表呢。 2.校内实践个人认为对找工作几乎没帮助,建议换成和测开有关的项目,实在没得写留着也行。 3.工作经历完全看不出来是干什么的,起码看着和计算机没啥关系,建议加强描述,写点你在工作期间的实际产出、解决了什么问题。 4.个人简述大而空,看着像AI生成,感觉问题最大。“Python,C,C++成为我打造高效稳定服务的得力工具”、“我渴望凭借自身技术知识与创新能力,推动人工智能技术的应用发展,助力社会实现智能化转型”有种小学作文的美感。而且你确定你个人简述里写的你都会嘛?你AI这块写的什么“深入研究”,发几篇顶会的硕博生都不一定敢这么写。而且你AI这块的能力和软测也完全无关啊。个人简述建议写你对哪些技术栈、哪些语言、哪些生产工具的掌握,写的有条理些,而且最好是和测开强相关的。
点赞 评论 收藏
分享
06-23 10:26
佳木斯大学 Java
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-16 18:05
何尝不是一种学历歧视呢
下午吃泡馍:这种公司不投也罢,不过建议挂出公司名字,1.1w就应激到问是不是清北也是看得出来不是啥好公司了,估计这hr也没见过啥世面
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务