超详细!终于搞明白KMP算法

超详细!终于搞明白KMP算法这里就会使用到「串的模式匹配算法」,最常见的分别是传统的「Brute-Force(暴力)算法」和「KMP算法」。 在BF算法中,每次失配都需要回溯指向上次比较起始字符的下一个字符。通过观察发现:在回溯的时候,已匹配似乎「有一部分」没必要继续比较了,这样可以降低算法的「时间复杂度…

超详细!终于搞明白KMP算法

小伙伴们好久不见,今天将开设“数据结构与算法”专栏,一起梳理一遍硬核课程的重要知识点,那我们开始吧

正文

字符串匹配是计算机的基本任务之一,举个栗子,有一个字符串“aaaaaaca“,我想知道里面是否包含另一个字符串“aaaac”,该怎么办?

这里就会使用到串的模式匹配算法,最常见的分别是传统的Brute-Force(暴力)算法KMP算法

BF算法设计思想

1、主串和模式串逐个字符进行比较

超详细!终于搞明白KMP算法

2、当出现字符串不相同时,也就是失配时,主串的比较位置重置为起始位置的下一个字符位置,模式串的比较位置重置为起始位置

超详细!终于搞明白KMP算法

3、匹配成功后返回主串中匹配串的起始位置,否则就返回错误代码

BF算法的设计缺陷及解决方案

在BF算法中,每次失配都需要回溯指向上次比较起始字符的下一个字符。通过观察发现:在回溯的时候,已匹配似乎有一部分没必要继续比较了,这样可以降低算法的时间复杂度

超详细!终于搞明白KMP算法

KMP算法的出现有效地解决了BF算法的缺陷。KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的。

但是这种算法相对于BF算法不太容易理解,网上也有很多解释,但配图有点少,总感觉差点意思,下面我通过画图的方式详细介绍KMP算法的设计思想和工作原理

KMP算法设计思想

在匹配过程中出现字符比较不相等时,主串 S已比较的位置不回溯,模式串 T比较的位置进行移动

超详细!终于搞明白KMP算法

在匹配过程中有一个难题需要解决:如何计算模式串 T失配时的移动位数?经过三位牛人的研究,设计出了部分匹配函数

部分匹配函数

部分匹配函数是KMP算法中最难以理解的部分。首先需要理解前缀后缀最大共有长度的概念。

· 前缀:指除了最后一个字符以外,一个字符串的全部头部组合

· 后缀:指除了第一个字符以外,一个字符串的全部尾部组合

超详细!终于搞明白KMP算法

· 最大共有长度(部分匹配值):指前缀和后缀中的最大共有元素,没有则为0。例如“abab”的前缀为“a”、“ab”、“aba”,后缀为“b”、“ab”、“bab”,最大共有元素为“ab”,所以最大共有长度为 2

回顾一下KMP算法的匹配过程:

超详细!终于搞明白KMP算法

红线框出的部分恰好就是失配时已匹配部分,“aaaa” 的最大共有元素为 “aaa”,这一部分字符就是不需要再重复进行比较直接跳过的字符

超详细!终于搞明白KMP算法

在代码实现过程中,j 移动后的位置 = 模式串 T 的起始位置下标 + 部分匹配值。通常起始下标为 0,因此 j 移动后位置 = 部分匹配值,即 j = next[j],next[j] 就是部分匹配函数,j 为失配时的位置

因此接下来就成了对部分匹配函数的是实现。将 “aaaac” 以首字符起始的所有子串的最大共有长度枚举出来,构成部分匹配表,它描述了失配时的下标 j 与部分匹配值的关系

超详细!终于搞明白KMP算法

部分匹配表则是通过模式串 T 的自匹配实现:

超详细!终于搞明白KMP算法

示例代码(C语言哦):

/*KMP匹配算法*/
int KMPCompare(HString parent, HString child, intpos) {
 int next[255];
 Get_Next(child, next);
 int i = pos - 1;
 int j = 0;     //j用于子串child中的起始位置
 while (i < parent.length && j < child.length) {
  if (j == 0 || parent.ch[i] == child.ch[j]) {
   ++i;
   ++j;
  }
  else {
   j = next[j];    //i不变,j后退
  }
 }
 if (j == child.length) {
  return (i + 1) - j;
 }
 return 0;
}

/*部分匹配函数的实现*/
void Get_Next(HString child, int * next) {
 int i = 0;
 int j = -1;
 next[0] = -1;   //不会用到
 while (i < child.length) {
  if (j == -1 || child.ch[i] == child.ch[j]) {
   ++i;
   ++j;
   next[i] = j;
  }
  else {
   j = next[j];
  }
 }
}

void main() {
 /*使用KMP算法匹配串*/
 HString parent, child;
 StrAssign_HeapString(&parent, "BBC ABCDAB ABCDABCDABDE");
 StrAssign_HeapString(&child, "ABCDABD");
 printf("Index = %d\n", KMPCompare(parent, child, 1)); } 

关注即可提高学习效率!我是Aime菌,下期再见!Peace~

每天进步一点点,慢一点才能走得更快

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13742.html

(0)

相关推荐

  • mysql配置优化「建议收藏」

    mysql配置优化「建议收藏」将这个参数设为0或大于1以上的数值会提高数据库的性能,但同时会伴随数据丢失的风险。二进制日志文件涉及到数据的恢复,以及想在主从之间获得最大的一致性,那么应该将该参数设置为1,但同时也会造成一定的性能损

    2023-04-15
    151
  • 深度神经网络压缩与加速技术

    深度神经网络压缩与加速技术随着深度神经网络使用的越来越多,相应的压缩和加速技术也孕育而生。LiveVideoStackCon 2023上海站邀请到了胡浩基教授为我们分享他们实验室的一些实践。

    2023-11-17
    174
  • 【JDBC】笔记(1)-[亲测有效]

    【JDBC】笔记(1)-[亲测有效]2、JDBC的本质是什么?JDBC是SUN公司制定的一套接口(实质); java.sql.*; (这个软件包下有很多接口)

    2023-05-03
    164
  • redis专项进阶课_redis项目

    redis专项进阶课_redis项目通过简单的KV数据库理解Redis 分为访问模块,操作模块,索引模块,存储模块 底层数据结构 除了String类型,其他类型都是一个键对应一个集合,键值对的存储结构采用哈希表 哈希表由多个哈希桶组成,

    2023-05-30
    149
  • 连锁便利店管理系统的六大作用[亲测有效]

    连锁便利店管理系统的六大作用[亲测有效]连锁便利店是一种商业模式,是以连锁加盟的方式扩大规模和影响力的零售业。随着科技的不断进步,连锁便利店管理系统已经成为了便利店管理的一种重要手段。

    2023-07-03
    129
  • hadoop 实时计算_flink写入hdfs

    hadoop 实时计算_flink写入hdfs一、概述 Flink核心是一个流式的数据流执行引擎,并且能够基于同一个Flink运行时,提供支持流处理和批处理两种类型应用。其针对数据流的分布式计算提供了数据分布,数据通信及容错机制等功能。基于流执行

    2023-05-15
    154
  • 入门Python:了解Python编程语言基础知识

    入门Python:了解Python编程语言基础知识Python是一种高级编程语言,具有简洁、易读、易学等优点。它被广泛应用于计算、数据分析、网络编程、Web开发、人工智能等领域。本文将介绍Python的基础知识,帮助初学者了解Python。

    2024-01-26
    96
  • Python def

    Python defPython def 是 Python 语言中定义函数的关键字,它是编写高质量、可重用的代码的基础。在 Python 中,函数是一组语句,用于执行特定任务。使用 def 关键字定义函数后,可以在程序的其他地方调用该函数。

    2024-08-13
    25

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注