(String)是由零个或多个任意字符组成的有限序列。如下图所示

目录

一、BF算法

二、KMP算法

一、前缀、后缀,最大公共前后缀

二、研究KMP与BF的区别 (主要是回溯)

三、next数组的讲解

j 位置的确定 (即next数组的详解)


当n=0时,为空串,与空格串不同。

一个串中任意个连续字符组成的子序列(包含空串)成为该串的子串。子串的概念类似于数学中的集合,有真子串,如下图所示

 图来自于bilibili 王卓老师

具体初始化,创建等就不讲了,实际开发中不可默守陈规,关键在于学习两种算法

一、BF算法

此算法也称为简单匹配算法。实际上即是暴力穷举法,算法时间复杂度为O(n*m),为方便理解算法先看下面图解

若刚开始S[0]!=T[0],条件同样满足,因此只要S[s]!=T[t],回溯就成立。循环此步骤的条件为s,t均小于该串长度

 当前面元素都满足条件S[s]==T[t],且进行到T[t]=="/0"时,代表匹配到了字符。此算法每次都要回溯因此时间复杂度为0(n*m)

代码实现如下(我以字符数组为例主要演示算法)

char S[7] = {"abcacbb"};char T[4] = {"cacb"};int s = 0;int t=0;while (s<sizeof(S)&&t< sizeof(T)) {    //j范围在主串内,t范围在子串内if (S[s]==T[t]) {s++;t++;    //值相等则比较下一元素}else {s = s - t + 1;    //回溯子串主串t= 0;}if (T[t]=="/0") {return 1;        //找到了}else {return 0;       //还未到循环结束}    }

二、KMP算法

KMP算法主要是在回溯方面进行了优化,使得不至于傻瓜式的回溯到头,关键点在于找到最大前后缀以减少无谓的过程。

由于网上的讲法有很多,我这面主要拆分为完整过程next数组两部分讲解,我这面归纳总结为以下几个步骤:

KMP算法流程

①前缀,后缀,最大公共前后缀 概念

②研究KMP与BF的区别 (主要是回溯)

③next数组的讲解

一、前缀、后缀,最大公共前后缀

前后缀的概念直接看如下范例,解释起来不如看例子理解的快,这个地方无需考虑原理什么的,就是需要用到这三个概念。当做平常知识即可,
有一条字符串 为  “abcde” 
前缀的集合:{a,ab,abc,abcd}
后缀的集合:{e,de,cde,bcde}
公共缀:就是该字符串 前缀后缀都包含的元素如下图所示
最大公共前后缀:如图中所示字符串“a b c a b d a”有 公共的前后缀为 a,b,ab三种情况,但最大的公共前后缀 就为ab.
失配位:即不相等时的位置。

 那么最大公共前后缀有什么意义呢?接下来就进入正题。(本段思路来自天勤考研)

我们设定主串为 S[11]={"abcabbbabc"},子串为 T[5]={"abcabc"},i,j分别为数组下标

如下图所示,S[i]T[j] 分别对应,直到 i=j=5时,即第六个元素时,二者不相等
当遇到不相等的情况是,BF的算法是将i回溯到 i-j+1 的位置,即之前比较的后一个位置
然而对于Kmp算法则不同,Kmp首先找到主串子串相同的部分的最大公共前后缀,
其次将子串的前缀挪到与主串后缀的地方对齐。再进行S[i]T[j] 的比较。

总结:步骤为  ①找到 失配位 ② 找到最大公共前后缀     

二、研究KMP与BF的区别 (主要是回溯)

那么为什么可以直接跳过这些元素而直接比较呢,即为什么 i 可以不回溯,j回溯位置也不用从头开始呢。那么接下来就进行此步骤的剖析:

当遇到不相等元素时证明主串子串在此元素之前一定都相等。那么先看相等这一部分,如图所示,若子串向移动,不管移动多少次,子串头元素a只有遇到后缀a时才会相等。那么同理b也是,因此我们直接找到最大公共前后缀,进行对齐即可。这里的移动只是方便看图,实际上移动的 只有 j  。这里的最大公共前后缀是在失配位之前寻找,(即绿线之前)
由此步骤我们得出代码如下所示

图片来自bilibili 懒猫老师 

BF算法在本文上面有提到,那么Kmp算法与其不同的地方主要在于判定条件,与回溯两处。此处判定条件 j=-1 会越界因此要加上条件,具体在后面会有讲到。j=next[j] 是 j 的回溯条件,即如何确定 S[i]T[j] 不相等时,j 的回溯位置 !!!再此强调 i 是不用回溯的,敌动我不动即可。只有在匹配成功后才会和 j 一同跳到下一个位置。

三、next数组的讲解

那么以上所有步骤,就是Kmp算法的整体架构,接下来我们只需要考虑 next 数组了,同时这里也是最关键的地方 !!!

next数组的意义在于找到每次  S[i]T[j] 不相等时,即失配位时,j 的回溯位置 , 这里我们先以手算法,讲解以便于理解后面的代码部分

事实上,在我们“移动”的过程中,根本不需要看主串,只需要看 子串(模式串)即可,直接将字串的最大前缀移动到最大后缀出即可如下图所示。此时我们再此强调,所谓的移动指示假想的,实际上是 j 的移动,如图 j 从原来失配位移动到了后缀之后。

j 位置的确定 (即next数组的详解)

一、手算图解法

此法仅仅为了方便观察对应代码来思考方便理解。(这里我们用的一组子串来演示)

由上图可知,想要判断最大公共前后缀只需要子串即可,那么我们制作以下表格

这里的 T 代表了子串(模式串)后面数值为 子串内容,下标为串数组对应下标,next即为 j 要回溯的位置。
注意:这里next不同视频教程,有不同的版本,大概讲解一下,其实就是各个位右移的区别。
本文采用第二种方式 (这里不懂下面讲)

next数组的求法

第一步:数组初始化:

我们设定  j 为前缀 i 为后缀 。数组初始化 j 就等于0,对应的数组元素就等于 a,i为后缀所以 i=3,此时的 j 对应的 next值即为 -1.这里可以是0,也可以是-1,对应的上面的表,那么数组外部的 j=next [] =-1; 此时就对应之前的判断条件,为什么要加上j=-1。

第二步:求next [ j ]的值

求法是前n项 是否有公共前后缀,没有填0,有一个则填1,有两个填2,以此类推 
当 j =-0时,数组初始化,  next [1] = -1;
 当 j =1 时,前面就只有a一个元素,所以   next [1] 应该为 0;
 当 j =2 时,前面有a b  两个元素,  所以    next [2] 应该为 0;
 当 j =3 时,前面有a b a 三个元素,所以    next [3] 应该为 1;(有公共前后缀 a)
后面以此类推,结果如下表

二、代码解法

将图表和代码结合看

总结:j 始终指向 a的位置,移动的为 i ,当遇到 j==-1 或 T [ i]=T [ j ]时才会+1,进行下一元素比较,如果相等其实是代表了最大公共前后缀有2位,若不相等,则证明只有一位最大公共前后缀,与此同时,j=next[ j ],也就是回退到值等于a的地方。

KMP算法和BF算法相关推荐

  1. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

  2. 操作系统之存储管理——FIFO算法和LRU算法

    操作系统之进程调度--优先权法和轮转法(附上样例讲解) 操作系统之银行家算法-详解流程及案例数据 操作系统之多线程编程-读者优先/写者优先详解 操作系统之存储管理--FIFO算法和LRU算法 操作系统 ...

  3. Prim算法和Kruskal算法

       Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...

  4. 基于Huffman算法和LZ77算法的文件压缩的改进方向

    基于Huffman算法和LZ77算法的文件压缩(八) 到这里已经简单实现基于Huffman算法和LZ77算法的文件压缩, GitHub源码:点我 根据基于Huffman算法和LZ77算法的文件压缩(七 ...

  5. 最短路径Dijkstra算法和Floyd算法整理、

    转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径-Dijkstra算法和Floyd算法 Dijks ...

  6. 用Spark学习FP Tree算法和PrefixSpan算法

    在FP Tree算法原理总结和PrefixSpan算法原理总结中,我们对FP Tree和PrefixSpan这两种关联算法的原理做了总结,这里就从实践的角度介绍如何使用这两个算法.由于scikit-l ...

  7. 游戏中DDA算法和Bresenham算法的应用

    在角色扮演或即时战略游戏中,经常会将角色以最佳的方式走到指定地点.游戏场景的地面情况复杂,而且场面大,若采用盲目式搜索,例如盲目穷举法,则几乎要遍历整个场景,效率非常低,造成角色反应速度过慢,实践证明 ...

  8. 【Java数据结构与算法】第二十章 Dijkstra算法和Floyd算法

    第二十章 Dijkstra算法和Floyd算法 文章目录 第二十章 Dijkstra算法和Floyd算法 一.Dijkstra算法 1.介绍 2.代码实现 二.Floyd算法 1.介绍 2.代码实现 ...

  9. 【Java数据结构与算法】第十九章 贪心算法、Prim算法和Kruskal算法

    第十九章 贪心算法.Prim算法和Kruskal算法 文章目录 第十九章 贪心算法.Prim算法和Kruskal算法 一.贪心算法 1.介绍 2.支付问题 二.Prim算法 1.最小生成树 2.介绍 ...

最新文章

  1. api.dll自己的理解
  2. jQuery的Accordion插件
  3. 你有一笔新订单 语音_上市即成爆款 哪吒V首日订单突破1200辆_搜狐汽车
  4. WPF 模仿QQ音乐首页歌单效果
  5. 修改ant design vue中的Icon图标颜色
  6. log4j自定义配置文件(SpringMVC项目)
  7. 携号转网将于明年在全国范围内实施
  8. 达梦工作笔记-达梦客户端,执行命令后要保存退出,才生效
  9. JAVA学习篇--Java类加载
  10. 如何用c语言编写工程文件夹,利用makefile实现c语言项目编译
  11. Spring 官方又孵化了个顶级项目,或将改变前后端API现状!
  12. 2017-07-12 周三 今日总结
  13. 5.1 Zend_Log_Writer
  14. 吾不是爱管闲事,实在是忍无可忍
  15. Linux-3.10-x86_64 内核配置选项简介
  16. Swiper.js实现无缝滚动
  17. Word文档被限制编辑了怎么办?
  18. python 笔记6:格式化时间缩写
  19. RGB-Infrared Cross-Modality Person Re-Identification---阅读
  20. 安全渗透测试-win7

热门文章

  1. Cas(05)——修改Cas的其它配置
  2. 安装包免费下载(持续更新ing…)
  3. 最新Laysns仿ZB响应式CMS轻主题 可做资源娱乐网
  4. kafka命令及启动
  5. 苹果应用商店AppStore审核中文指南(译本)
  6. android面试资料
  7. 本地 Services(服务)
  8. 设置文本框 input [type=text] 的长度不超过固定值,输入的字符不超过固定值
  9. java实现魔方_闲来无事,用java写了一个魔方小程序。附源码 | 学步园
  10. 【CEPH-初识篇】ceph详细介绍+“ 一 ” 篇解决ceph集群搭建, “ 三 ” 大(对象、块、文件)存储使用