KMP 算法 + 运用前后缀信息 + 案例分析 + 实战力扣题

news2024/11/6 15:30:40

一、理解KMP算法如何运用后缀前缀的信息

  • 文本串text:abcxabcdabxabcdabcdabcy
  • 模式串pattern:abcdabcy

当发现不匹配的点,我们的目标不是在这个串中进行回溯操作。因此我们要检查的是 d 的前面的子串(abc),在这个子串(abc)是否存在后缀与前缀相同的情况。所有的字符都是单独的,因此这里没有后缀与前缀相同的情况,因此意味着我们下一个比较对象将从 x a 开始,再一次地,我们将会理解得更好在这个例子当中。

此时发现还是匹配失败,而 j = 0,退无可退了,那么就 i++;(指向下一个位置)

匹配成功的话就 i++; j++;

i 指向 x j 指向 c 的时候,发生匹配失败!因此再一次地,我们检查c 前面的子串(abcdab)中,是否存在前后缀相同的情况,且取最长的,发现 ab 最长的公共前后缀。这意味着,在 xc 发生不匹配时,x 左边的子串一定是 ab。因此也意味着,因为 x 左边的子串ab子串(abcdab)后缀是一定相同的子串(abcdab)后缀其前缀也一定是相同的故不需要再次去匹配前缀(ab);下一次匹配可以从 x c(pattern[2]) 开始。

也就是说,我们不需要在主串中向前回顾,去寻找下一个匹配点在哪里,现在我们从 x这里开始,那是因为这个子串(abcdab)的后缀(ab)也是前缀(ab),而后缀(ab)已经和x 左边的子串ab匹配过了,那么没有理由再去匹配一遍前缀(ab)了,因此我们从x c开始匹配 

此时 xc 匹配失败,我们检查 c 前面的子串(ab)是否存在前后缀相同的情况,发现没有!因此意味着我们下一个比较对象将从 x a 开始

此时发现还是匹配失败,而 j = 0,退无可退了,那么就 i++;(指向下一个位置)

匹配成功的话就 i++; j++;

i 指向j 指向 y 的时候,发生匹配失败!我们检查 y 前面的子串(abcdabc)是否存在前后缀相同的情况,且取最长的,发现 abc 最长的公共前后缀。这意味着,在 d 和 y 发生不匹配时,y 之前的已经匹配了,y之前的子串(abcdabc)的后缀(abc)文本串中 d 的前面子串(abc)相同。而子串(abcdabc)的后缀(abc)和前缀(abc)相同,可以说后缀也是前缀,那么就没有理由再一次去匹配abc。下一次比较可以从模式串的d开始,也就是从当前文本串的 和 模式串的 开始匹配 

匹配成功的话就 i++; j++;

此时 i 越界,j 越界(匹配成功),结束!

二、D数组

此时 pattern[i] != pattern[j],即 b != a,匹配失败,此时 j = 0,继续 i++


此时 pattern[i] != pattern[j],即 c != a,匹配失败,此时 j = 0,继续 i++


此时 pattern[i] != pattern[j],即 d != a,匹配失败,此时 j = 0,继续 i++


此时 pattern[i] == pattern[j],即 a == a,匹配成功,此时记录D[i] = ++j;即 j = 1,D[4] = 1; 然后继续i++;(注意 j++ 操作已经在 D[i] = ++j 中了)


此时 pattern[i] == pattern[j],即 b == b,匹配成功,此时记录D[i] = ++j;即 j = 2,D[5] = 2; 然后继续i++;(注意 j++ 操作已经在 D[i] = ++j 中了)


此时 pattern[i] == pattern[j],即 c == c,匹配成功,此时记录D[i] = ++j;即 j = 3,D[6] = 3; 然后继续i++;(注意 j++ 操作已经在 D[i] = ++j 中了)


此时 pattern[i] != pattern[j],即 a != d,匹配失败,此时 j = 3,执行 j = D[j-1]; 即 j = D[3-1] = D[2] = 0;

那么 j = 0;继续判断 j 和 i 所指向的字符是否匹配


此时 pattern[i] == pattern[j],即 a == a,匹配成功,此时记录D[i] = ++j;即 j = 1,D[7] = 1; 然后继续i++;(注意 j++ 操作已经在 D[i] = ++j 中了)


此时 i 越界,终止!


探究一下,这其中的一个值的意义,以此类推:

这意味着在子串abcda最大公共前后缀为a,其前后缀相同都为a,因此我们匹配了 后缀a 文本串 x 前面的子串a,也就意味着 前缀a 文本串 x 前面的子串a已经匹配了,所以下一个我们检查的是 x 和 b

C++代码:

#include<iostream>
#include<string>
using namespace std;

void print_matching_result(string s, int start) {
    for (int i = 0; i < start; i++)
        cout << " ";
    cout<<s<<endl;
}

void getD(int D[], string pattern) {
    int i = 1, j = 0;
    int np = pattern.size();
    while (i < np) {
        if (pattern[i] == pattern[j]) {
            D[i] = ++j;
            i++;
            // 也可以简化:D[i++] = ++j;
        }
        else {
            if (j > 0) j = D[j - 1];
            else i++;
        }
    }
}

void kmp(string text, string pattern) {
    cout << "**********************************************" << endl;
    cout << text << endl;
    int i = 0, j = 0, nt = text.size(), np = pattern.size();
    int* D = new int[np]();
    getD(D, pattern);
    while (i < nt) {
        if (pattern[j] == text[i]) {
            i++, j++;
            if (j == np) {
                print_matching_result(pattern, i - j);
                j = D[np - 1];
            }
        }
        else {
            if (j > 0) j = D[j - 1];
            else i++;
        }
    }
}

int main()
{
    kmp("ABABABABC", "ABAB");
    kmp("ABABCABAB", "ABAB");
    kmp("AAAAAAA", "AAA");
    kmp("ABABABC", "ABABC");
    kmp("XYXZdeOXZZKWXYZ", "WXYZ");
    kmp("GCAATGCCTATGTGACCTATGTG", "TATGTG");
    kmp("AGATACGATATATAC", "ATATA");
    kmp("CATCGCGGAGAGTATAGCAGAGAG", "GCAGAGAG");
    return 0;
}

我的往期文章(详解KMP算法核心原理:j = D[j-1]):

KMP 算法 + 详细笔记 + 核心分析 j = D[j-1]-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_41987016/article/details/133848188?spm=1001.2014.3001.5501参考和推荐B站视频:

【中文字幕】Knuth–Morris–Pratt(KMP)_Pattern_Matching(Substring_search)_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV18k4y1m7Ar?p=1&vd_source=a934d7fc6f47698a29dac90a922ba5a3

实战力扣题,感兴趣的话可以看一下我的往期文章:

leetCode 214.最短回文串 + KMP-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_41987016/article/details/133915196?spm=1001.2014.3001.5501

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1115228.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2000-2021年全国30省市水土流失治理面积、水库数量、水库总容量、除涝面积数据

2000-2021年全国30省市水土流失治理面积、水库数量、水库总容量、除涝面积数据 1、时间&#xff1a;1995-2020年 2、指标&#xff1a;水土流失治理面积、水库数量、水库总容量、除涝面积 3、范围:30省市不含上海 4、来源&#xff1a;国家统计J、各省NJ 5、指标解释&#x…

优秀数据库模式迁移工具的发展历程

数据库模式迁移可能是应用程序开发中风险最大的领域——因为这是一个困难的、有风险的和痛苦的过程。数据库模式迁移工具的存在是为了减轻这种痛苦&#xff0c;并且已经取得了长足的进步&#xff1a;从基本的CLI工具到GUI工具&#xff0c;从简单的SQL GUI客户端到一体化协作数据…

[牛客]计算机网络习题笔记_1020

1、物理层&#xff1a;以太网 调制解调器 电力线通信(PLC) SONET/SDH G.709 光导纤维 同轴电缆 双绞线等。 2、数据链路层&#xff08;网络接口层包括物理层和数据链路层&#xff09;&#xff1a;Wi-Fi(IEEE 802.11) WiMAX(IEEE 802.16) ATM DTM 令牌环 以太网 FDD…

在JavaScript中,如何创建一个数组或对象?

在JavaScript中,可以使用以下方式创建数组和对象: 一:创建数组(Array): 1:使用数组字面量(Array Literal)语法,使用方括号 [] 包裹元素,并用逗号分隔: let array1 = []; // 空数组 let array2 = [1, 2, 3]; // 包含三个数字的数组 let array3 = [apple, banana,…

HypeX Labs:充分释放加密资产的潜力

加密货币通常被视为是资产类别或投资工具&#xff0c;不过其代表了一种全新的意识形态&#xff0c;且与传统资产有着完全不同的底层价值逻辑&#xff0c;所以它们不仅可以被视为一种资产类别或投资工具&#xff0c;在大多数情况下可以被视为一种基于技术的实现。因此我们可以认…

C++练习:人员信息管理程序计算不同职员的每月工资。

要求编写一个简单的人员信息管理程序&#xff0c;具体要求如下&#xff1a; 程序涉及到五个类&#xff0c;分别是employee&#xff0c;technician&#xff0c;salesman&#xff0c;manager&#xff0c;salsemanager。 这五个类的关系为&#xff1a;employee是顶层父类&#xf…

AUTOSAR AP 硬核知识点梳理(3)AUTOSAR AP 方法论和开发流程的最佳实践

一 Adaptive AUTOSAR 方法论 AUTOSAR AP开发方法论包括三个主要阶段,分别是: 1、架构和设计阶段: 在这个阶段,您需要确定系统的需求、功能和服务,并将它们分配到合适的Machine上。 根据个人习惯使用一些建模工具,例如[Simulink]、[ProVision]或[RTA-VRTE SDK]自带的DS…

我们不一样①

我们不一样① 从hello world开始 别人的hello world​​ 我们的hello world 代码展示 #include <stdio.h> int main(){printf("\033[31mhello world\033[0m"); getchar();return 0; } 此处用了 ANSI转义序列 ANSI转义序列是一种带内信号的转义序列标准&am…

代码随想录算法训练营第23期day27|93.复原IP地址、78.子集、90.子集II

目录 一、&#xff08;leetcode 93&#xff09;复原IP地址 二、&#xff08;leetcode 78&#xff09;子集 三、&#xff08;leetcode 90&#xff09;子集II 一、&#xff08;leetcode 93&#xff09;复原IP地址 力扣题目链接 状态&#xff1a;没有写出来&#xff0c;待回顾…

Python —— 验证码的处理执行JavaScript语句

1、验证码的处理 1、概述&绕过验证码的方案 很多的网站都在登录页面加入了识别文字&#xff0c;识别图片&#xff0c;拖动拼图的验证码方式来防止爬虫、恶意注册 等&#xff0c;如果是做自动化&#xff0c;需要绕过验证码才能进入下一步操作&#xff0c;那么有4种方案可以…

深入探讨 Golang 中的追加操作

通过实际示例探索 Golang 中的追加操作 简介 在 Golang 编程领域&#xff0c;append 操作是一种多才多艺的工具&#xff0c;使开发人员能够动态扩展切片、数组、文件和字符串。在这篇正式的博客文章中&#xff0c;我们将踏上一段旅程&#xff0c;深入探讨在 Golang 中进行追加…

基于跳蛛优化的BP神经网络(分类应用) - 附代码

基于跳蛛优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于跳蛛优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.跳蛛优化BP神经网络3.1 BP神经网络参数设置3.2 跳蛛算法应用 4.测试结果&#xff1a;5.M…

eltable el-tooltip__popper 换行、字体、颜色等调整

show-overflow-tooltip属性 element-ui表格 默认情况下若内容过多会折行显示&#xff0c;若需要单行显示可以使用show-overflow-tooltip属性&#xff0c;它接受一个Boolean&#xff0c;为true时多余的内容会在 hover 时以 tooltip 的形式显示出来。 默认情况 element-ui表格 sh…

【练习题】二.栈和队列

1.蒋编号为0和[的两个栈存放于一个数组空间 V[m]中,栈底分别处于数组的两端。当第0号栈的栈顶播针 top[0]等F-1 时该戍为空:当第1号栈的栈顶指针 top[I]等于 m 时,该栈为空两个栈均从两端向中间增长 (见图 3.2)。试编写双栈初始化,判渐栈空、栈满、进栈和出栈等算法的两数。…

5年经验之谈 —— 总结自动化测试与性能测试的区别!

很多刚刚接触自动化测试和性能测试的同学感觉性能测试和自动化测试是没什么区别的&#xff0c;就像小编刚刚接触自动化测试和性能测试的时候一样&#xff0c;区别就是&#xff1a;自动化测试是一个用户在测试&#xff0c;而性能测试需要并发&#xff0c;需要设计各种场景。测试…

论文辅助笔记:t2vec 数据预处理

1 波尔图数据 curl http://archive.ics.uci.edu/ml/machine-learning-databases/00339/train.csv.zip -o data/porto.csv.zip 这条命令使用 curl 从给定的URL下载一个名为 train.csv.zip 的压缩文件&#xff0c;并将其保存为 data/porto.csv.zip。 unzip data/porto.csv.zip 使…

python实现矩阵转置

使用列表推导式实现矩阵转置 matrix [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] print([[row[i] for row in matrix]for i in range(4)])使用内置函数来实现矩阵转置 matrix [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] print(list(map(list, zip(*matrix))))使用…

softplc windows 安装测试

下载 .NET 6.0 (Linux、macOS 和 Windows) 安装后 在这里 The command could not be loaded, possibly because: * You intended to execute a .NET application: The application restore does not exist. * You intended to execute a .NET SDK command: No…

如何利用IP定位技术进行反欺诈?

网络欺诈风险是指在互联网和数字领域中&#xff0c;存在各种类型的欺诈活动&#xff0c;旨在欺骗个人、组织或系统以获得非法获益。以下是一些常见的网络欺诈风险类型&#xff1a; 身份盗用&#xff1a;这是一种欺诈行为&#xff0c;涉及盗取他人的个人身份信息&#xff0c;如姓…

基于Java的汽车维修预约管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…