一篇优质的Knuth-Morris-Pratt算法讲解

2024-03-22 11:10

本文主要是介绍一篇优质的Knuth-Morris-Pratt算法讲解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 部分匹配表
    • 如何使用部分匹配表

部分匹配表

KMP的关键是部分匹配表。我和理解KMP之间的主要障碍是我没有完全理解部分匹配表中的值的真正含义。我现在将尽可能用最简单的话来解释它们。

下面是模式“ABABABACA”的部分匹配表:
在这里插入图片描述
如果我有一个八个字符的模式(在本例的持续时间内,让我们说“abababca”),我的部分匹配表将有八个单元格。如果我看表中的第八个也是最后一个单元格,我对整个模式感兴趣(“abababca”)。如果我看表中的第七个单元格,我只对模式中的前七个字符(“ababac”)感兴趣;第八个(“a”)是不相关的,可以从建筑物或其他东西上掉下来。如果我看到桌子上的第六个单元格,你会明白的。请注意,我还没有讨论每个单元格的含义,只是讨论了它所指的内容。
现在,为了讨论词义,我们需要知道正确的前缀后缀

正确前缀:字符串中的所有字符,末尾有一个或多个字符被截断。“S”、“Sn”、“Sna”和“Snap”都是“Snap”的正确前缀。

正确后缀:字符串中的所有字符,开头有一个或多个字符被截断。“agrid”、“grid”、“rid”、“id”和“d”都是“Hagrid”的适当后缀。

考虑到这一点,我现在可以给出部分匹配表中值的一句话含义:

(子)模式中与同一(子)模式中的正确后缀匹配的最长正确前缀的长度。

让我们来看看我的意思。假设我们在第三间牢房里。从上面你会记得,这意味着我们只对前三个字符(“aba”)感兴趣。在“aba”中,有两个适当的前缀(“a”和“ab”)和两个适当的后缀(“a”和“ba”)。正确的前缀“ab”与两个正确的后缀都不匹配。但是,正确的前缀“a”与正确的后缀“a”匹配。因此,在本例中,与正确后缀匹配的最长正确前缀的长度为1。

让我们在第四牢房试试。这里,我们对前四个字符(“abab”)感兴趣。我们有三个合适的前缀(“a”、“ab”和“aba”)和三个合适的后缀(“b”、“ab”和“bab”)。这一次,“ab”在两者中,有两个字符长,所以第四单元的值为2。

因为这是一个有趣的例子,让我们也在涉及“ababa”的第五单元中尝试一下。我们有四个适当的前缀(“a”、“ab”、“aba”和“abab”)和四个适当的后缀(“a”、“ba”、“aba”和“baba”)。现在,我们有两个匹配项:“a”和“aba”都是正确的前缀和后缀。因为“aba”比“a”长,所以它获胜,第五单元的值为3。

让我们跳到第七单元(倒数第二个单元),它与模式“ababac”有关。即使没有列举所有正确的前缀和后缀,也应该很明显不会有任何匹配项;所有后缀都将以字母“c”结尾,没有一个前缀将以字母“c”结尾。由于没有匹配项,第七单元得到0。

最后,让我们看看第八单元,它涉及整个模式(“阿巴巴卡”)。由于它们都以“a”开头和结尾,我们知道该值至少为1。然而,这就是它的终点;长度为2及以上时,所有后缀都包含c,而只有最后一个前缀(“ababac”)包含c。这个七个字符的前缀与七个字符的后缀(“bababca”)不匹配,所以第八单元得到1。

如何使用部分匹配表

当我们发现部分匹配时,可以使用部分匹配表中的值提前跳过(而不是重复不必要的旧比较)。公式的工作原理如下:

如果找到长度为partial_match_length的部分匹配,并且表[partial_match_length]>1,我们可以跳过partial_match_length-表[partial_match_length-1]字符。

假设我们将模式“abababca”与文本“bacbabab”进行匹配。这是我们的部分匹配表,便于参考:
在这里插入图片描述

我们第一次得到部分匹配是在这里:
在这里插入图片描述
This is a partial_match_length of 1. The value at table[partial_match_length - 1] (or table[0]) is 0, so we don’t get to skip ahead any. The next partial match we get is here:
在这里插入图片描述

这是5的部分匹配长度。表[partial_match_length-1](或表[4])中的值为3。这意味着我们可以提前跳过部分匹配长度表[partial\u match\u length-1](或5表[4]或5-3或2)字符:
在这里插入图片描述
这是3的部分匹配长度。表[partial_match_length-1](或表[2])中的值为1。这意味着我们可以提前跳过部分匹配长度表[部分匹配长度-1](或3表[2]或3-1或2)字符:
在这里插入图片描述此时,我们的模式比文本中的其余字符长,因此我们知道不存在匹配。

这篇关于一篇优质的Knuth-Morris-Pratt算法讲解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/835180

相关文章

Java进程CPU使用率过高排查步骤详细讲解

《Java进程CPU使用率过高排查步骤详细讲解》:本文主要介绍Java进程CPU使用率过高排查的相关资料,针对Java进程CPU使用率高的问题,我们可以遵循以下步骤进行排查和优化,文中通过代码介绍... 目录前言一、初步定位问题1.1 确认进程状态1.2 确定Java进程ID1.3 快速生成线程堆栈二、分析

javascript fetch 用法讲解

《javascriptfetch用法讲解》fetch是一个现代化的JavaScriptAPI,用于发送网络请求并获取资源,它是浏览器提供的全局方法,可以替代传统的XMLHttpRequest,这篇... 目录1. 基本语法1.1 语法1.2 示例:简单 GET 请求2. Response 对象3. 配置请求

Java Stream.reduce()方法操作实际案例讲解

《JavaStream.reduce()方法操作实际案例讲解》reduce是JavaStreamAPI中的一个核心操作,用于将流中的元素组合起来产生单个结果,:本文主要介绍JavaStream.... 目录一、reduce的基本概念1. 什么是reduce操作2. reduce方法的三种形式二、reduce

CSS引入方式和选择符的讲解和运用小结

《CSS引入方式和选择符的讲解和运用小结》CSS即层叠样式表,是一种用于描述网页文档(如HTML或XML)外观和格式的样式表语言,它主要用于将网页内容的呈现(外观)和结构(内容)分离,从而实现... 目录一、前言二、css 是什么三、CSS 引入方式1、行内样式2、内部样式表3、链入外部样式表四、CSS 选

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++