KMP算法理解

2023-11-17

学习了KMP算法,对此有了一些理解,通过博客分享,如有理解错误的地方,请纠正!

字符串的前缀后缀

再说明KMP算法前见说下它用到的一些东西。给定一个字符串如 “ABCDAB”,那么它的前缀就是除去最后一个字符的所有串即“ABCDA,ABCD, ABC,AB,A”,同理,后缀是出去第一个字符的串即“BCDAB,CDAB,DAB,AB,A”,而在KMP算法中我们要用到要匹配串的子串的前缀后缀的最大公共长度。我们还用“ABCDAB”这个串举例。

各个子串 前缀 后缀 最大公共长度
A 0
AB A B 0
ABC AB,A BC,B 0
ABCD ABC,AB,A BCD,CD,D 0
ABCDA ABCD,ABC,AB,A BCDA,CDA,DA,A 1
ABCDAB ABCDA,ABCD,ABC,AB,A BCDAB,CDAB,DAB,AB,A 2

所以你可以用一个数组来记录出各个子串的前缀后缀最大公共长度

A B C D A B
0 0 0 0 1 2

最大公共长度数组获取

这里面的思想有些类似动态规划,我们用图来说明下。这里把数组命名为arr,字符数组为str
我们知道字符串的第一个字符的子串没有前后缀,公共长度一定为0
所以我们从后面开始 J表示后缀与前缀相同的最大公共长度,有上面的表格可以看出来要想出现前后缀相同,肯定是前缀的头和后缀的尾相等。
在这里插入图片描述
所以这里判断str[j]与str[i]是否相等,结果不等,故子串“AB”没有前缀和后缀相同的的子串即
在这里插入图片描述
同理看子串“ABC”和子串“ABCD”中也是没有相同的前缀和后缀即
在这里插入图片描述
到了这里我们发现arr[j] == arr[i],即子串“ABCDA”中的前缀“A”和后缀的“B”相等,j++即
在这里插入图片描述
当前的最大长度是1,我们发现arr[j] == arr[i],所以很容易可以推出子串“ABCDAB”中的前缀“AB”和后缀“AB”相等,故现在的最大长度是 j++ = 2 ,同理“ABCDABC”和“ABCDABCD”子串也符合当前的情况即
在这里插入图片描述
到这里我们发现arr[j] != arr[i],故不能通过前面的最大长度去推该子串的最大长度,j = 4>0,所以我们要回溯到这一连续的前后缀相等的上一个状态,即让 j = arr[j-1],此时j = 0故正好在字符‘A’处,也正是判断子串“ABCDA”是否有前后缀相同的时候,只不过这是我们看的就是“ABCDABCDE”中前缀“A”和“E”是否相同了,结果不同。此时J = 0,没有前后缀相等的时候故“ABCDABCDE”这个子串也就没有相同的前后缀。即
在这里插入图片描述
附上代码

void getArr(char* str,int** arr){
    int len = strlen(str);
    *arr = (int *)malloc(sizeof(int) * len);
    (*arr)[0] = 0;
    for (int i = 1,j=0; i <len ; ++i) {
        while (j>0 && str[j] != str[i])
            j = (*arr)[j-1];
        if (str[j] == str[i])
            j++;
        (*arr)[i] = j;
    }
}

KMP算法

现在我们开始讲解KMP算法,它可以解决这样一个问题:有一个文本串S,和一个模式串P,查找P在S中的位置中第一次出现的位置。我们用图来说明这个算法。变量j表示匹配到相等元素的个数,str1为总串,str2为模式串

在这里插入图片描述
首先判断“C”与"A"不相等,子串向后面移动一位"B"与"A"也不相等子串继续往后移动寻找匹配即

在这里插入图片描述
直到找到相等这时j++,继续匹配下面直到遇到“D”!=“B”时
在这里插入图片描述
如果用暴力我们就会用把子串在整体向后移动一位,让模式串中的第一个字符“A”与总串的“B”进行匹配即

在这里插入图片描述

但是我们会发现这样要浪费很多时间,做无用的判断。KMP算法的解决方案是计算最大的移动位数,减少时间。我们看上面的图,要想再完全匹配到总串,只要找到后面总串中出现与模式串首字母一样的位置,才有可以总串之后的与模式串相匹配即

在这里插入图片描述
让子串移动到这里,这样是不是就移动了4位,比之前移动1位的效率高很多。那么移动的这四位是怎么计算出来的呢?
在这里插入图片描述
在模式串“B”时匹配失败,即我们可以查到“ABCDAB”这个串的前缀后缀公共元素最大长度是2,前面已经匹配成功5个字符了,我们用匹配成功的字符-失败的上字符的最大长度 即 5-1=4,即子串向后移动4位。可以和上面求arr类比 j=arr[j-1] 即j=1 即

在这里插入图片描述
此时先恰好是“B”与“D”匹配失败 j此时是1 1-0=1,即模式串向后移动一位此时J=0即

在这里插入图片描述
继续依次匹配,直到出现总串与模式串相等的时候即

在这里插入图片描述
之后"A" == “A”,“B” == “B” …… 此时 j=6=str2的长度,说明匹配成功,返回此时str1的数组下标即可。

int Search(char* str1,char* str2){
    int* arr;
    getArr(str2,&arr);
    int len = strlen(str1);
    for (int i = 0,j = 0; i <len ; ++i) {
        while (j>0 && str1[i] != str2[j])
            j = arr[j-1];
        if (str1[i] == str2[j])
            j++;
        if (j == strlen(str2)){
            free(arr);
            arr = NULL;
            return i-j+1;
        }
    }
    free(arr);
    arr = NULL;
    return -1;
}

还有一种数组存储是在前后缀最大值公共长度数组的基础上演变的即next表即

在这里插入图片描述
很明显此时表是把最大值公共长度整体移动一位,前一位补-1,这样的好处则是在判断要移动模式串最大位数是直接用 完成匹配数-失败位的next中的值即可。

时间复杂度

我们分析下KMP算法的时间复杂度,生成数组,时间复杂度可估算为O(m),遍历主串可以估算为O(n),所以KMP算法的整体时间复杂度是O(m+n),m是模式串的长度,n是主串的长度。
我们在再分析下暴力,对主串遍历一番遇到匹配再和模式串匹配,不符合,从主串的下一位接着匹配。总体时间复杂度就是O(m*n)了!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

KMP算法理解 的相关文章

  • 01背包问题变种:从长度为n的数组里选出m个数使和为固定值sum

    这个问题是我从leetcode上一道问题所想到的 原题 如果是从数组中选出2个数相加使之成为固定的数sum 这当然很简单 把数组中的数字遍历一遍 判断另一个数字是否也在数组中即可 代码如下 vector
  • Mysql 数据库

    数据库基础 1 什么是数据库 用来存储数据 数据库可在硬盘及内存中存储数据 数据库与文件存储数据的区别 数据库本质也是通过文件来存储数据 数据库的概念就是系统的管理存储数据的文件 数据库介绍 本质就是存储数据的C S架构的socket套接字
  • 算法--将数组分成和相等的多个子数组,求子数组的最大个数

    作者 陈太汉 一个整数数组 长度为n 将其分为m份 使各份的和相等 求m的最大值 比如 3 2 4 3 6 可以分成 3 2 4 3 6 m 1 3 6 2 4 3 m 2 3 3 2 4 6 m 3 所以m的最大值为3 算法 原理的思想是
  • 将二叉树转为有序的双向链表

    一 题目要求 输入一棵二叉排序树 现在要将该二叉排序树转换成一个有序的双向链表 而且在转换的过程中 不能创建任何新的结点 只能调整树中的结点指针的指向来实现 include
  • BP神经网络与Python实现

    人工神经网络是一种经典的机器学习模型 随着深度学习的发展神经网络模型日益完善 联想大家熟悉的回归问题 神经网络模型实际上是根据训练样本创造出一个多维输入多维输出的函数 并使用该函数进行预测 网络的训练过程即为调节该函数参数提高预测精度的过程
  • LeetCode83: 删除排序链表中的重复元素

    给定一个已排序的链表的头 head 删除所有重复的元素 使每个元素只出现一次 返回 已排序的链表 示例 1 输入 head 1 1 2 输出 1 2 示例 2 输入 head 1 1 2 3 3 输出 1 2 3 提示 链表中节点数目在范围
  • 数据结构之链表与线性表

    数据结构之链表与线性表 线性表 顺序线性表 顺序表 顺序线性表 使用数组实现 一组地址连续的存储单元 数组大小有两种方式指定 一是静态分配 二是动态扩展 优点 随机访问特性 查找O 1 时间 存储密度高 逻辑上相邻的元素 物理上也相邻 缺点
  • 第二十八节、基于深度学习的目标检测算法的综述(附代码,并附有一些算法英文翻译文章链接))...

    在前面几节中 我们已经介绍了什么是目标检测 以及如何进行目标检测 还提及了滑动窗口 bounding box 以及IOU 非极大值抑制等概念 这里将会综述一下当前目标检测的研究成果 并对几个经典的目标检测算法进行概述 本文内容来自基于深度学
  • 常用的十种算法--马踏棋盘算法

    1 马踏棋盘算法介绍 马踏棋盘算法也被称为骑士周游问题 将马随机放在国际象棋的 8 8 棋盘 Board 0 7 0 7 的某个方格中 马按走棋规则 马走日字 进行移动 要求每个方格只进入一次 走遍棋盘上全部 64 个方格 2 马踏棋盘算法
  • 数据结构与算法学习总结(六)——字符串的模式匹配算法

    基本概念 字符串是一种特殊的线性表 即元素都是 字符 的线性表 字符是组成字符串的基本单位 字符的取值依赖于字符集 例如二进制的字符集为0 1 则取值只能为 0 1 再比如英语语言 则包括26个字母外加标点符号 例如 abcde 就是一个字
  • Python 实现列队

    1 列队定义 队列是项的有序结合 其中添加新项的一端称为队尾 移除项的一端称为队首 当一个元素从队尾进入队列时 一直向队首移动 直到它成为下一个需要移除的元素为止 最近添加的元素必须在队尾等待 集合中存活时间最长的元素在队首 这种排序成为
  • 图 - Java实现无向带权图的邻接矩阵表示法

    图 Java实现无向带权图的邻接矩阵表示法 1 图 1 1 图的介绍 图 Graph 是一种复杂的非线性表结构 图中的元素我们就叫做顶点 vertex 图中的一个顶点可以与任意其他顶点建立连接关系 我们把这种建立的关系叫做边 edge 跟顶
  • 算法学习——贪心算法之币种统计

    算法描述 币种统计 单位给每一位员工发工资 精确到元 为了保证不临时换零钱 使得每个员工取款的张数最少 在取工资前统计所有员工所需要的各种票面的张数 约定票种为100 50 20 10 5 2 1元 并验证币种统计是否正确 算法思路 算法描
  • 数据结构与算法-列表(双向链表)设计及其排序算法

    0 概述 本文主要涵盖列表 双向链表 的设计及其排序算法的总结 列表是一种典型的动态存储结构 其中的数据 分散为一系列称作节点 node 的单位 节点之间通过指针相互索引和访问 为了引入新节点或删除原有节点 只需在局部调整少量相关节点之间的
  • Linux下进程退出的几种形式

    进程退出 Linux 下进程的退出分为正常退出和异常退出两种 1 正常退出 a 在main 函数中执行return b 调用exit 函数 c 调用 exit 函数 2 异常退出 a 调用about函数 b 进程收到某个信号 而该信号使程序
  • 区块链中的哈希算法

    区块链中的密码学 密码学在区块链中的应用主要有两个 哈希算法与非对称加密算法 这次主要对哈希算法进行详细的说明 哈希算法 哈希算法的特点有 1 输入可以为任意大小的字符串 2 产生固定大小的输出 3 可以在合理的时间内算出输出值 若要满足密
  • 插入排序超详解释,一看就懂

    目录 一 插入排序的相关概念 1 基本思想 2 基本操作 有序插入 二 插入排序的种类 三 直接插入排序 1 直接插入排序的过程 顺序查找法查找插入位置 2 使用 哨兵 直接插入排序 四 直接插入排序算法描述 五 折半插入排序 1 查找插入
  • 【数据结构】双链表的定义和操作

    目录 1 双链表的定义 2 双链表的创建和初始化 3 双链表的插入节点操作 4 双链表的删除节点操作 5 双链表的查找节点操作 6 双链表的更新节点操作 7 完整代码 嗨 我是 Filotimo 很高兴与大家相识 希望我的博客能对你有所帮助
  • 排序:计数排序

    一 概念 计数排序是非比较排序 是对哈希直接定址法的变形应用 二 思想 利用数组统计相同数据出现的次数 例如整型数据m出现n次 就在数组m位置记录数据为n 最后从头遍历数组打印数据即可 通俗来讲就是 数组下标即为数据 下标所指位置的值即为数
  • 高精度运算合集,加减乘除,快速幂,详细代码,OJ链接

    文章目录 零 前言 一 加法 高精度加法步骤 P1601 A B 二 减法 高精度减法步骤

随机推荐

  • windows下C盘文件夹管理员权限设置

    我们有时会将一些软件安装在C盘 却发现有时程序对C盘文件增删改操作失败 然后自己手动去执行时也经常弹出 你需要提供管理员权限才能进删除此文件 之类 这很烦 网上有些说法是开启Administrator用户 但是我这种有点洁癖的不喜欢增加一个
  • java b 类型_什么类型的Java类型是“[B”?

    我试图通过Java代码 Hibernate 从MySQL DB获取MD5加密传递 但我不能得到字符串或任何合理的Java类型 我唯一得到的是这个无益的信息 java lang ClassCastException B无法转换为com mys
  • 封装与检测技术

    环氧树脂 环氧树脂是一种高分子聚合物 分子式为 C 11 H 12 O 3
  • 复杂的密码有多重要?实操暴力破解wifi密码......

    暴力破解就是穷举法 将密码字典中每一个密码依次去与握手包中的密码进行匹配 直到匹配成功 注意 私自破解他人WiFi属于违法行为 本教程仅供学习与参考 破解工具 破解工具 kali linux系统 本教程使用的装在物理机的linux系统 虚拟
  • postgresql 中输入逃逸字符\n\r\b\t

    例如 1 建表 create table test a1 text a2 varchar 100 a3 char 200 2 插入数据 使用关键字 E insert into test a1 a2 a3 values E aaa n aaa
  • linux ssh服务是否已经启动?

    linux ssh服务是否已经启动 突然想到 ubuntu貌似默认是不会安装ssh server的 会默认安装ssh client 恍然大悟 是不是因为这个原因 于是查看发现 果然没有安装 下面进行安装openssh server sudo
  • Linux系统常用基本命令总结

    Linux基本命令 Linux的简介 Linux的厂商 Linux的目录结构 基于虚拟机的环境搭建 常用命令与示例 一 文件基本操作命令 1 ls命令 2 pwd命令 3 mkdir命令 4 cd命令 5 touch命令 6 cp命令 7
  • ubuntu13.10 64位系统下载Android源码

    参考http source android com source downloading html进行下载 下载过程中出现的问题参考http blog 163 com aravarcv 126 blog static 12384272820
  • (超级详细)如何在Mac OS上的VScode中配置OpenGL环境并编译

    文章目录 安装环境 下载GLAD与GLFW 一 下载GLAD 二 下载GLFW 项目结构配置 测试程序与项目的编译 测试可执行文件HelloGL 安装环境 机器 macbook air 芯片 M1芯片 arm64 macOS macOS V
  • SHA-256算法实现过程

    整理一下SHA 256的实现步骤 1 定义8个32位常量 h0 0x6a09e667 h1 0xbb67ae85 h2 0x3c6ef372 h3 0xa54ff53a h4 0x510e527f h5 0x9b05688c h6 0x1f
  • 通过Java理解Kruskal算法

    今天 我将解析一段Java代码 该代码实现了Kruskal算法 用于在连通的无向图中找到最小生成树 首先 我们来了解一些关键组件 1 DisjointSet 不相交集 这是Kruskal算法中的辅助数据结构 用于管理不相交集的集合 Find
  • msvcr100.dll丢失的解决方法?三招解决msvcr100.dll丢失问题

    最近我遇到了一个电脑问题 就是在运行某个软件时提示缺少msvcr100 dll文件 起初我并不知道这个文件是什么 也不知道它的作用 但通过一番搜索和了解 我对这个问题有了更深的理解 并且也得到了解决的办法 解决方法一 确保你的两台电脑都是相
  • requests_模拟搜狗翻译

    01笔记 在搜狗翻译的url中 请求的方法是Post 所以我们需要通过requests post方法来请求数据 接着url的请求参数是一个字典 所以我们需要修改该字典参数的搜索关键词 且其他参数需复制请求 否则请求不到数据 最后该url返回
  • PyTorch 2.0来了!100%向后兼容,一行代码训练提速76%

    编辑 机器之心 点击下方卡片 关注 自动驾驶之心 公众号 ADAS巨卷干货 即可获取 点击进入 自动驾驶之心 全栈算法 技术交流群 PyTorch 官方 我们这次的新特性太好用了 所以就直接叫 2 0 了 前段时间 PyTorch 团队在官
  • Altium Designer-Net has no driving source警告消除的方法

    1 其实这个警告原因是 你图中有一个器件的管脚有属性 如I O 并且这个管脚设定了驱动源 你先从元件库中 找到这个管脚 把管脚的属性 改成下面图片 的这个样子 就好了 2 下面这种方法 只是快速 逃避警告 也是可以通过编译的 在进行原理图编
  • 爬取豆瓣电影数据并进行分析可视化

    学习爬虫爬取豆瓣电影数据并进行分析 整体流程如下 1 爬取豆瓣电影数据 2 读取豆瓣电影数据 3 统计各个电影的评论数 4 读取某个电影的全部评论内容 5 获取某个电影的关键词并生成词云图 6 对电影数据的关键词和评分进行辩证分析并生成热力
  • linux设备号

    什么是设备号 linux中设备号是用来标记一类设备以及区分这类设备中具体个体的一组号码 由主设备号和次设备号组成 主设备号用来标记设备的类型 次设备号用来区分在这类设备中具体的个体设备 为什么用设备号 我们知道 linux下一切皆文件 li
  • CentOS 8.5:mysql8 + php8 使用 phpmyadmin52

    使用 dnf 安装命令没有安装成功 下载安装 phpmyadmin 下载地址 最新版本为 5 2 phpMyAdmin Downloads etc nginx nginx conf 中的配置内容 server listen 80 liste
  • VS Code的神级插件Bito - GPT-4 和 ChatGPT 编写代码、解释代码、创建测试

    Bito是什么 Bito是一款插件 它目前支持VS Code Chrome插件 以及Jetbrains的全系列IDE 例如 IDEA PyCharm Clion等 可以说能够覆盖大部分开发同学了 Bito 通过将 GPT 4 和 ChatG
  • KMP算法理解

    学习了KMP算法 对此有了一些理解 通过博客分享 如有理解错误的地方 请纠正 文章目录 字符串的前缀后缀 最大公共长度数组获取 KMP算法 时间复杂度 字符串的前缀后缀 再说明KMP算法前见说下它用到的一些东西 给定一个字符串如 ABCDA