博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
KMP算法介绍总结
阅读量:4949 次
发布时间:2019-06-11

本文共 1928 字,大约阅读时间需要 6 分钟。

KMP算法介绍总结

KMP算法来源

KMP算法英文是(Knuth-Morris-Pratt),它是以三个发明者命名的,起头的K代表的是著名科学家Donald Knuth.其最常用于字符串匹配,查询。

算法说明

一般我们匹配字符串的时候,我们从目标字符串dstr(假设长度为n)的第一个下标选取和sptr长度(长度为m)一样的子字符串进行比较,如果一样,就返回开始处的下标值,不一样,选取str下一个下标,同样选取长度为n的字符串进行比较,直到str的末尾(实际比较时,下标移动到n-m).这样的时间复杂度是O(m*n)。而使用KMP算法的复杂度是O(m+n)。

那KMP是如何简化时间复杂度的了?利用目标字符串dstr的性质(比如里面部分字符串的重复性,即使不存在重复字段,在比较时,实现最大的移动量)。举例说明:有一个字符串“BBC ABCDAB ABCDABCDABDE”,想知道,里面是否包含字符串""ABCDABD"?
image

  1. 看上图所示:字符串“BBC ABCDAB ABCDABCDABDE”的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较,因为B与A不匹配,所以搜索词后移一位。
  2. 往后移动一位以后,还是不一致,继续移动。知道第一位相同 ,此时情况如下所示:
    image
  3. 第一个字符的数字相同后,继续比较第2个字符,也完全相同
    image
    直到有一个字符不完全相同:
    image
    D对应的是空格。此时常规的做法就是将搜索词整个后移一位,然后再依次进行比较。但是这样做,因为你需要从第2位开始,依次进行比较,那些曾经比过的位。但此时的实际情况却是:当D与空格不相匹配的时候,你实际上是知道签名六个字符是“ABCDAB”的。KMP算法就是利用了这个信息,不把搜索的起始位置移动到已经比较过的位置,继续把他向后移动,避免了来回移动,从而提高效率,但这样,假如刚好有一个子串从第2位开始能匹配上不是就遗漏了吗?
  4. KMP 当然不是随意的移动,是有一定规则的。这个规则就是《部分匹配表》或者也称之为Next表。这是当前例子的Next表:image
  5. 我们先暂时不管,这种表是如何产生的和为什么,先按照这张表进行位移。当我们发现空格与D不匹配,前面6个字符“ABCDAB”是匹配的时候。查表可值,最后一个匹配字符B对应的“部分匹配值”是2,按照下面的公式计算向后移动的位数:
移动位数 = 已匹配的字符数-对应的部分匹配值

从上面的公式我们可以得出:6-2=4,所以将搜索词向后移动4位,到达下面的位置。image

  1. 移动了4位以后,再次依次比较,发现空格与C不匹配,此时,已匹配的字符数为2(“AB”),对应的“部分匹配值”为0,所以移动位数为2,于是往后再移动2位。image
  2. 空格与A不匹配。直接后移动一位。image,此时C与D不匹配。匹配的字符数为6,部分匹配值为2,6-2=4,移动4位。image
  3. 此时发现完全匹配了。此时如果还要继续找出所有的匹配值,则7-0=7,移动7位继续往下即可。
  4. 从上面可以看出KMP算法非常重要的点就是得出Next表。image
    这里先介绍“前缀”和“后缀”。“前缀”指除了最后一个字符以外,一个字符串的全部头部组合;“后缀”指除了第一个字符以外,一个字符串的全部尾部组合。
    “部分匹配值就是”前缀“和”后缀“的最长的共有元素的长度。
  • "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
    以上就是Next表的计算方法。其实,"部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度)。搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置。

参考文档:

转载于:https://www.cnblogs.com/angellst/p/7778381.html

你可能感兴趣的文章
scala的REPL shell的调用
查看>>
SQL中Group By的使用
查看>>
Mybatis映射原理,动态SQL,log4j
查看>>
哪个微信编辑器比较好用?
查看>>
错误org/aopalliance/intercept/MethodInterceptor解决方法
查看>>
Pylint在项目中的使用
查看>>
使用nginx做反向代理和负载均衡效果图
查看>>
access remote libvirtd
查看>>
gdb调试中出现No symbol table is loaded. Use the "file" command.问题
查看>>
(4) Orchard 开发之 Page 的信息存在哪?
查看>>
ASP.NET中 GridView(网格视图)的使用前台绑定
查看>>
图像加载
查看>>
关于zxing生成二维码,在微信长按识别不了问题
查看>>
Haskell学习-高阶函数
查看>>
手动通知扫描SD卡主动生成缩略图
查看>>
js中tagName和nodeName
查看>>
PC-XP系统忘记密码怎么办
查看>>
Android实例-打电话、发短信和邮件,取得手机IMEI号(XE8+小米2)
查看>>
深入了解Oracle ASM(二):ASM File number 1 文件目录
查看>>
SQL数据库学习系列之一
查看>>