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
  • 50个c/c++源代码网站

    C C 是最主要的编程语言 这里列出了50名优秀网站和网页清单 这些网站提供c c 源代码 这份清单提供了源代码的链接以及它们的小说明 我已尽力包括最佳的C C 源代码的网站 这不是一个完整的清单 您有建议可以联系我 我将欢迎您的建 议 以
  • LeetCode83: 删除排序链表中的重复元素

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

    数据结构之链表与线性表 线性表 顺序线性表 顺序表 顺序线性表 使用数组实现 一组地址连续的存储单元 数组大小有两种方式指定 一是静态分配 二是动态扩展 优点 随机访问特性 查找O 1 时间 存储密度高 逻辑上相邻的元素 物理上也相邻 缺点
  • findBug 错误修改指南

    FindBugs错误修改指南 1 EC UNRELATED TYPES Bug Call to equals comparing different types Pattern id EC UNRELATED TYPES type EC c
  • 常用的十种算法--马踏棋盘算法

    1 马踏棋盘算法介绍 马踏棋盘算法也被称为骑士周游问题 将马随机放在国际象棋的 8 8 棋盘 Board 0 7 0 7 的某个方格中 马按走棋规则 马走日字 进行移动 要求每个方格只进入一次 走遍棋盘上全部 64 个方格 2 马踏棋盘算法
  • SDUT--OJ《数据结构与算法》实践能力专题训练6 图论

    A 数据结构实验之图论一 基于邻接矩阵的广度优先搜索遍历 Description 给定一个无向连通图 顶点编号从0到n 1 用广度优先搜索 BFS 遍历 输出从某个顶点出发的遍历序列 同一个结点的同层邻接点 节点编号小的优先遍历 Input
  • 递归算法中的时间复杂度分析

    对于一种算法的时间复杂度分析还是特别重要的 在一些非递归算法中 我们仅仅看运算次数最多的那一行代码可能执行多少次就可以 实际就是看在循环中变量的变化 但是对于递归算法中该怎么分析呢 下面介绍几种递归函数中的算法时间复杂度分析的方法 0 递推
  • Hash映射理解

    先说数组 数组优点之一 能通过索引很快定位到值 hashmap 就是利用了数组这个优点 对比 线性映射 定义一个数组 数组的元素是结构体 结构体包括 一对键 值 伪代码表示 a 0 struct Bill 5 a 1 struct KK 6
  • 亚利桑那州立大学周纵苇:研习 U-Net ——现有的分割网络创新

    雷锋网AI研习社按 经典的 Encoder Decoder 结构在目标分割问题中展现出了举足轻重的作用 然而这样一个相对固定的框架使得模型在感受野大小和边界分割精度两方面很难达到兼顾 本次公开课 讲者以 U Net 为案例分析 总结现有的分
  • 数据结构小白之插入排序算法

    1 插入排序 1 1 思路 将n个需要排序的元素看成两个部分 一个是有序部分 一个是无序部分 开始的时候有序表只有一个元素 无序表有n 1个元素 排序过程中每次从无序表中取出元素 然后插入到有序表的适当位置 从而成为新的有序表 类似排队 如
  • JavaScript系列——数组元素左右移动N位算法实现

    引言 在自己刚刚毕业不久的时候 去了一家公司面试 面试官现场考了我这道题 我记忆深刻 当时没有想到思路 毫无疑问被面试官当成菜鸟了 最近刚好在研究数组的各种算法实现 就想到这道题 可以拿来实现一下 纪念自己逝去的青春 需求 假设有这样一个数
  • 4Sum

    Given an array S of n integers are there elements a b c and d in S such that a b c d target Find all unique quadruplets
  • OJ-合并两个有序链表

    题目描述 代码如下 Definition for singly linked list struct ListNode int val struct ListNode next struct ListNode mergeTwoLists s
  • 时间复杂度+常见复杂度解释

    前言 算法的效率 虽然计算机能快速的完成运算处理 但实际上 它也需要根据输入数据的大小和算法效率来消耗一定的处理器资源 要想编写出能高效运行的程序 我们就需要考虑到算法的效率 算法的效率主要由以下两个复杂度来评估 时间复杂度 评估执行程序所
  • 用两个栈实现队列

    目录 一 栈的基本结构及其接口 二 我的队列结构定义 三 我的队列创建及其初始化 四 我的队列入队 五 我的队列出队 六 我的队列取队头元素 七 我的队列判空 八 我的队列销毁 一 栈的基本结构及其接口 栈的结构定义 typedef int
  • 【数据结构入门精讲 | 第二篇】一文讲清算法复杂度

    上篇文章中我们引入了算法 数据结构 数据类型等概念 而要想衡量一个算法与数据结构是否为优质的 就需要一个衡量标准 这个衡量标准也是在我们实现一个好的算法时要遵循的原则 目录 基本概念 渐进性态 渐进性态数学表征 算法复杂度的运算 顺序搜索算
  • 【数据结构】单链表的定义和操作

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

    HashMap的知识点可以说在面试中经常被问到 是Java中比较常见的一种数据结构 所以这一篇就通过源码来深入理解下HashMap 1 HashMap的底层是如何实现的 基于JDK8 1 1 HashMap的类结构和成员 HashMap继承
  • 浅谈归并排序:合并 K 个升序链表的归并解法

    在面试中遇到了这道题 如何实现多个升序链表的合并 这是 LeetCode 上的一道原题 题目具体如下 用归并实现合并 K 个升序链表 LeetCode 23 合并K个升序链表 给你一个链表数组 每个链表都已经按升序排列 请你将所有链表合并到

随机推荐

  • 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