KMP算法

原创 2016年05月31日 23:46:43

这种算法不太容易理解,网上有很多解释,但读起来都很费劲。直到读到Jake Boxer的文章,我才真正理解这种算法。下面,我用自己的语言,试图写一篇比较好懂的KMP算法解释。

  1.

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

  2.

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

  3.

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

  4.

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

  5.

  直到字符串有一个字符,与搜索词对应的字符不相同为止。

  6.

  这时,最自然的反应是,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把"搜索位置"移到已经比较过的位置,重比一遍。

  7.

  一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。

  8.

  怎么做到这一点呢?可以针对搜索词,算出一张《部分匹配表》(Partial Match Table)。这张表是如何产生的,后面再介绍,这里只要会用就可以了。

  9.

  已知空格与D不匹配时,前面六个字符"ABCDAB"是匹配的。查表可知,最后一个匹配字符B对应的"部分匹配值"为2,因此按照下面的公式算出向后移动的位数:

  移动位数 = 已匹配的字符数 - 对应的部分匹配值

  因为 6 - 2 等于4,所以将搜索词向后移动4位。

  10.

  因为空格与C不匹配,搜索词还要继续往后移。这时,已匹配的字符数为2("AB"),对应的"部分匹配值"为0。所以,移动位数 = 2 - 0,结果为 2,于是将搜索词向后移2位。

  11.

  因为空格与A不匹配,继续后移一位。

  12.

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

  13.

  逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。如果还要继续搜索(即找出全部匹配),移动位数 = 7 - 0,再将搜索词向后移动7位,这里就不再重复了。

  14.

  下面介绍《部分匹配表》是如何产生的。

  首先,要了解两个概念:"前缀"和"后缀"。 "前缀"指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。

  15.

  "部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,

  - "A"的前缀和后缀都为空集,共有元素的长度为0;

  - "AB"的前缀为[A],后缀为[B],共有元素的长度为0;

  - "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;

  - "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;

  - "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;

  - "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;

  - "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。

  16.

  "部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度)。搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置。




版权声明:本文为博主原创文章,未经博主允许不得转载。

KMP算法应用

KMP算法应用题目描述: 给定一个字符串,求其中出现重复的任意一个字符?再求其中最长的重复子串?题目分析: 如果明白KMP原理,明白next数组next[j]=k的具体含义,这样的题目可以用nex...
  • zxc995293774
  • zxc995293774
  • 2015年07月29日 20:38
  • 563

kmp算法总结

搞ACM也有三年了,期间学习了不少算法,到12月把上海站打完也要成退役狗了。最近突然想把学过的一些算法回过头来好好总结一下,于是就有了我的算法总结系列。这是这个系列的开端,所以先写一个简单点的算法,以...
  • dyx404514
  • dyx404514
  • 2014年11月20日 16:00
  • 3487

KMP算法的效率分析

上一节,我们研究了KMP算法的实现原理,这节,我们从分析的角度看看KMP算法的时间复杂度,通过分析证明,我们代码对算法的实现,是能保证线性复杂度的...
  • tyler_download
  • tyler_download
  • 2016年10月20日 12:55
  • 650

KMP简单证明

KMP第一遍不是特别容易理解,所以就琢磨着给出一个证明,来加深理解,所以就想出了下面这么个不是很正规和形式化的证明。关于KMP算法的流程可以搜索相关文章,比如这篇挺不错的。前提假设:目标文本串T的长度...
  • feilengcui008
  • feilengcui008
  • 2016年03月03日 17:45
  • 497

KMP算法next数组通俗理解,适合考研及基础学习者

KMP算法是主要用来做字符串的匹配,有一个文本次T和一个模式串P,就是拿模式串P去匹配文本串T。 匹配的步骤分为两步,先做模式串自身匹配,即求出next数组;然后在进行T与P的匹配。 那么...
  • wust_ZJX
  • wust_ZJX
  • 2016年11月20日 00:38
  • 763

KMP算法 Next数组详解(【洛谷3375】KMP字符串匹配 )

KMP算法题面题目描述如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。为了减少骗分的情况,接下来还要输出子串的前缀数组next。如果你不知道这是什么意思也不要问,...
  • qq_30974369
  • qq_30974369
  • 2017年07月03日 21:13
  • 958

KMP算法最浅显理解——一看就明白

说明KMP算法看懂了觉得特别简单,思路很简单,看不懂之前,查各种资料,看的稀里糊涂,即使网上最简单的解释,依然看的稀里糊涂。 我花了半天时间,争取用最短的篇幅大致搞明白这玩意到底是啥。 这里不扯概...
  • starstar1992
  • starstar1992
  • 2017年02月07日 17:41
  • 41673

KMP算法图解之过程实现

本文是图中的老人所写的中文版,作者是谁无法确定,毕竟转载已经让原作者消失在网络的海洋,不过我依然要在此表示对两位作者由衷的感谢。      读完本文,对KMP有了初步的认识,但文中对关键的部分匹...
  • u010232171
  • u010232171
  • 2014年12月15日 17:06
  • 756

改进的KMP算法

/*改进的字符串匹配算法 改进的KMP算法*/ #include #include #include int next[100];//全局变量 int KMP(char S[],char ...
  • silence2015
  • silence2015
  • 2016年02月22日 15:10
  • 1110

KMP算法及next数组详解

最近整理笔记时,突然翻出几年前理解起来困难无比的看毛片(KMP)算法,笔记中详述了搜索过程,图文并茂,然而在最最重要的next数组部分却是一带而过,于是找出当年的教材,也只是写了getnext()函数...
  • u012043391
  • u012043391
  • 2016年10月14日 18:21
  • 2435
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:KMP算法
举报原因:
原因补充:

(最多只允许输入30个字)