程序员必会算法-KMP算法
KMP算法是一种优秀的字符串匹配算法,字符串匹配的常规算法是一步一步进行移位和比较操作,直至找到完全相匹配的字符串。
下面通过一个例子,为大家仔细说明KMP算法的使用和思路:
问题:
在字符串“DEABCDABABCDABCDABDE”字符串中,匹配字符串"ABCDABD".
算法思路:
KMP算法的思路在于,根据已经匹配的部分字符的信息,不把搜索位置移回已经比较过的位置,这样就提高了效率,是不是还是有点不清楚?没关系,让我们来根据一个例子来切实体会一下KMP算法是如何实现的。
图解:
1、KMP算法的核心是一张“部分匹配表”,这个表是怎么来的,后面再说,先用了再说,下图就是该问题的部分匹配表。

这个表上面一行是我们的模式字符串,下面一行是每个字符所对应的匹配值
移位规则是 移动位数 = 已匹配的字符串长度 - 已匹配字符串的最后一位字符所对应的匹配值。
2、接下来就开始进行操作

上图中我们看到,移位两位后,我们找到了部分匹配的字符串"ABCDAB",但并没有找到完全匹配的字符串,如果是常规思路,就是在继续往下一步一步移位,但我们这里不这样进行,我们观察到,已经匹配的字符串长度是6,匹配到的最后一个字符是"B",查询部分匹配表,这个“B”的部分匹配值是2,那么根据我们算法的移位规则,下一步我们的移位长度 = 6 - 2 = 4;
3、

╮(╯▽╰)╭,有没有发现,移了4位之后,刚好到达了下一个“AB”处?是不是很神奇?好了,打住,我们继续往下移,当前已匹配的字符串长度为2,查询这个“B”的匹配值为0(别和上个B搞混了),根据算法,我们接下来移位长度是 2 - 0 = 2;
4、

继续,和前面的步骤相同,我们这次移位长度为 6 - 2 = 4;
5、

至此,我们已经找到了完全匹配的字符串,当然,如果母字符串的长度较长,我们可以继续进行移位,继续寻找,和之前的步骤相同,下次我们移位长度为 7 - 0 = 7。
算法分析:
不知道大家看到现在,有没有一点明悟?来,让我们分析一下模式字符串“ABCDABD”:
对于搜索来说,我们首先关注的肯定是第一个字符,如果第一个字符都不匹配,那么后面的字符就没有比较的必要了,该目标字符串的第一个字符是’A‘,让我们看看这个字符串里有没有’A‘,诶,还真有,假如说我们现在已经匹配了“ABCDA”,5个字符,我们要移4位才能从第一个'A'移到第二个'A',’A‘只有一个字符,5 - 1 = 4;
再往下看,关注完第一个字符,我们开始关注和第一个字符依次相连的子字符串,这些字符串有一个共性,就是第一个字符都是’A‘,那我们看看这种字符串能有多少,"AB","ABC","ABCD","ABCDA","ABCDAB","ABCDABD",再看看这些字符串在目标字符串“ABCDABD”中存在几个,可以看出,除去和第一个“A”相连的,“AB”还有一个,其余的没有,而"AB"长度为2,所以在表中,第二个B的匹配值为2。
该算法的核心思路在于,有时候,字符串的头部和尾部可能会有重复。
不知道大家有没有听懂?让我们把匹配字符串换一下,换成“ABCDABC”,现在的部分匹配表应该是:

算法思考和延伸:
如果模式字符串过长,部分匹配表的生成会占用较多的时间,如何去提高部分匹配表的生成效率,是该算法的优化所在。(个人观点,如有大佬,请指教!)
该算法思想和字典编码有一定的相通之处。改天我会写出一个字典编码的文章。敬请期待!
程序员必会算法-KMP算法的更多相关文章
- c++程序员必知的几个库
c++程序员必知的几个库 1.C++各大有名库的介绍——C++标准库 2.C++各大有名库的介绍——准标准库Boost 3.C++各大有名库的介绍——GUI 4.C++各大有名库的介绍——网络通信 5 ...
- 迈向高阶:优秀Android程序员必知必会的网络基础
1.前言 网络通信一直是Android项目里比较重要的一个模块,Android开源项目上出现过很多优秀的网络框架,从一开始只是一些对HttpClient和HttpUrlConnection简易封装使用 ...
- 程序员必知的8大排序(三)-------冒泡排序,快速排序(java实现)
程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现) 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现) 程序员必知的8大排序(三)-------冒 ...
- 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现)
程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现) 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现) 程序员必知的8大排序(三)-------冒 ...
- 程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现)
http://blog.csdn.net/pzhtpf/article/details/7559896 程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现) 程序员必知的8大 ...
- 值得花费一周研究的算法 -- KMP算法(indexOf)
KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...
- [置顶] 程序员必知(三):一分钟知道URI编码(encodeURI)
因为浏览器会用一些特殊的字符作为特定的意义,所以在要传输的内容上如果有这些特殊的字符的话,就需要对其进行转义才能正确传输,如以下字符为发送时候的关键字,即特殊字符 ;/?:@&=+$,# 所以 ...
- 数据结构与算法--KMP算法查找子字符串
数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章.这篇文章.还有这篇他们写得非常棒.结合他们的解释和自己的理解,完成了本文. 上一节介绍了暴力法查找子字符串,同时也发 ...
- Android程序员必知必会的网络通信传输层协议——UDP和TCP
1.点评 互联网发展至今已经高度发达,而对于互联网应用(尤其即时通讯技术这一块)的开发者来说,网络编程是基础中的基础,只有更好地理解相关基础知识,对于应用层的开发才能做到游刃有余. 对于Android ...
- 程序员必知的8大排序(四)-------归并排序,基数排序(java实现)
程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现) 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现) 程序员必知的8大排序(三)-------冒 ...
随机推荐
- haproxy 配置文件分析
LOG 功能: 编辑/etc/rsyslog.conf 配置文件: # Provides UDP syslog reception $ModLoad imudp #需要启用 $UDPServerRun ...
- 物理层PHY 和 网络层MAC
PHY模块简介 物理层位于OSI最底层,物理层协议定义电气信号.线的状态.时钟要求.数据编码和数据传输用的连接器. 物理层的器件称为PHY. 上图里的灰色方框图里的就是PHY芯片内部模块图. MAC器 ...
- Java程序设计第三次作业
编写“学生”类及其测试类. 5.1 “学生”类: 类名:Student 属性:姓名.性别.年龄.学号.5门课程的成绩 方法1:在控制台输出各个属性的值. 方法2:计算平均成绩 方法3:输出各个属性的值 ...
- Android 全局使用第三方字体
给APP全局设置字体主要分为两个方面来介绍 一.给原生界面设置第三方字体 1.准备工作-下载第三方字体:传送门 将文件放入工程assets目录下.(一般个人习惯单独命名一个文件夹放字体文件,也可直接放 ...
- 记python使用grpc
using grpc in Python gRPC是基于http/2的RPC框架,使用ProtoBuf作为底层数据序列化.Nginx服务器2018年3月17日引入gRPC支持. gRPC 是用来实现跨 ...
- HTTP之gRPC
gRPC 官方文档 gRPC 是一个高性能.开源和通用的 RPC 框架,面向移动和 HTTP/2 设计. gRPC 基于 HTTP/2 标准设计,带来诸如双向流.流控.头部压缩.单 TCP 连接上的多 ...
- Qt Designer问题(挖坑)
同时用两个VS的Qt Designer打开.ui文件,关闭Qt Designer之后再打开发现Qt Designer不在打开方式了.要重启VS才行.
- 删除链表的倒数第N个节点(java实现)
题目: 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. 示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链 ...
- hive参数配置详细
hive.exec.mode.local.auto 决定 Hive 是否应该自动地根据输入文件大小,在本地运行(在GateWay运行) true hive.exec.mode.local.auto.i ...
- Spring mvc集成log4j2
前期环境 Spring mvc + Maven + Idea 一.下面开始配置log4j2,先简单演示其如何配置,再仔细了解log4j2用法. 1.1 配置pom.xml,引用log4j2相关包 & ...