本文主要参考了https://mp.weixin.qq.com/s/rbaPmBejID8-rYui35Snrg的表述,加上部分自己的理解

学习任何算法都要了解该算法解决什么问题?我们看看KMP算法主要解决什么问题。我们举一个例子,已知字符串1(ABCABBABAABBA)中查找字符串2(ABCAAB)是否存在,如果存在,字符串2在字符串1中的起始位置是多少?

对于上面这个列子,我们很快就可以回答出来字符串2(ABCAAB)在字符串1中存在,起始位置为5(假设从0开始)

暴力匹配:

不考虑任何效率的问题,当然就是从头到尾比较过去了,比如:

ABCABBABAABBA

ABCAAB→

比较下来,发现从第4个字符开始不同了,那没办法,说明前5个字符不是我们想要的字串,接下来我们就让字符串往前拱一步,继续比较:

ABCABBABAABBA

ABCAAB→

这一轮更惨,第一个就栽了,没关系,继续死磕往前拱:

ABABCBABAABBA

ABCAAB→

这一轮也不咋滴,比较到第3个就歇菜了。只要我们有毅力,这个过程坚持不懈,总能找到(或者找不到)答案。

暴力求解算法的复杂度为:假设长字符串为n,短字符串为m,在最极端的情况下(只有最后m个字符才互相匹配)我们需要走n-m轮,每一轮需要匹配m次,时间复杂度为O(nm)

现在的问题是:有没有更快的方法来找到匹配的字串呢?

KMP算法

KMP算法的核心意思就是:当我们发现一次比较下来字串没有完全匹配的情况下,下一次的比较也许可以不止往前拱一步,也许可以拱N步,关键是,究竟可以拱几步呢?

搞清楚这个问题前,先来搞清楚一个关键信息:“部分匹配值”,官方的解释太啰嗦了,我掰开了揉碎了讲给你听,就是这样:将我们要匹配的字串写出来,写两遍:

ABCAAB→

←ABCAAB

看到了吧,我们让他们一个向左一个向右,相向而行。算一下上一行的右边跟下一行的左边,最多能有几个字符是重合的(注意上一行的首字符不参与这个游戏,否则每个字串都是从头配到尾,就没意思了),这个数值N就是字串ABAAB的所谓部分匹配值,当然,你会发现此时N等于2,因为:

后缀

ABCAAB

ABCAAB

前缀

下边的字串再往前走,再也找不到更多的重合的字符了,因此字串"ABAAB"的部分匹配值为2,记为:

ABCAAB

2

来,继续算部分匹配值,接下来缩短一点,将最右边的B去掉,来看ABAA的部分匹配值:

ABCAA

ABCAA

显而易见,字串"ABAA"的部分匹配值是1,记为:

ABCAAB

1 2

不断重复上述过程,将每一个字串的“部分匹配值”都算出来,就是所谓的部分匹配表,如下所示。

ABCAAB

00 01 12

好了,花开两朵各表一枝,说回刚刚提到的问题:发现不匹配之后,究竟要向右拱几步呢?答案是:可以往前拱 (N-x) 步。N指的是匹配的字符数,x是部分匹配值,现在我们再把刚开始的步骤再做一遍:

ABCABBABAABBA

ABCAAB→

比较下来发现有3个字符匹配,此时N=4,查表得知ABCA的部分匹配值x=1,因此我们此时可以往前拱 (4-1)步,接下来比较:

ABCABBABAABBA

ABCAAB→

  我想大家心中一定有这样一个疑问,为什么可以这样子移动,这样子移动不会漏掉匹配数据吗?

上面一行的红色字体ABCA的最后一个A其实就是ABCA的最长后缀

ABCABBABAABBA

        ABCAAB→

下面一行的红色字体的ABCA的第一个字符A其实就是最长前缀

我们移动的目的就是要让最长后缀(A)与最长的前缀(A)重合,也就是让两头的部分匹配的区段重合在一起

为什么可以这样子移动?

因为我们知道ABCA前后缀匹配部分只有A,也就是说ABCABBABAABBA的前缀AB与ABCA的后缀CA是不匹配的。

如果我们把小字符串ABCAAB中的A移动到与ABCABBABAABBA中A前面任何一个位置,比如C位置得到的上下字符一定不匹配,因为它们公共部分只有A

ABCABBABAABBA

     ABCAAB

         

你发现,此时我们就跳过了一些比较循环,让我们整个算法的效率得到极大的提升。其实KMP算法的核心,就是充分利用比较过的未能匹配的字串的信息,而不是一股脑将他们丢弃。

最新文章

  1. Web 架构师的能力(转)
  2. 原生态js,鼠标按下后,经过了那些单元格
  3. zboot/xtract.c
  4. 由<a href = "#" > 引发的思考
  5. Java编程 “提高性能” 应尽力做到
  6. HTML5 在<a>标签内放置块级元素
  7. Java~时间戳小知识
  8. Python_初识函数和返回值_22
  9. Component 父子组件关系
  10. Lombok自定义annotation扩展含Intellij插件
  11. cmdb安装脚本
  12. JAVA复习笔记之多线程并发
  13. 2-String to Integer (atoi)
  14. 20155229 2016-2017-2 《Java程序设计》第十周学习总结
  15. HTML5游戏开发系列教程6(译)
  16. Flask实战第68天:项目上线部署
  17. 【树形dp】Find Metal Mineral
  18. [BZOJ 2817] 波浪
  19. 内存空间申请(C)
  20. ADO之密码验证--3次错误就锁定『改进』

热门文章

  1. 博客内插入bilibili视频
  2. Unity3D - 设计模式 - 工厂模式
  3. HDU 1043 & POJ 1077 Eight(康托展开+BFS | IDA*)
  4. Linux系统——常见的系统调用
  5. web常见攻击总结
  6. Jmeter 设置HTTP RPS性能测试模型
  7. java课后作业-5
  8. vue项目中使用vue-awesome
  9. 球形空间产生器sphere(bzoj 1013)
  10. 洛谷P1279 字串距离