字符串之KMP详解

2023-11-09

昨晚梳理了一下KMP的过程,感觉印象深刻了不少,在此写下博客加深印象,同时也希望能和大家交流。

KMP这个名字来源于其三个创始人名字首字母,主要用于解决字符串的匹配问题。

字符串的匹配问题:假设有两个字符串S和T,问串T是否出现在串S中/串T在串S中出现了多少次。(假设串S的长度为n,串T的长度为m)

常规思路:

按照我们正常的想法,肯定是用T跟S的每一位一一匹配,一旦遇到不能匹配的时候,就将正在匹配的起始位置右移一个,即起始位置+1,然后依然与T进行一一匹配,直到匹配成功为止,否则T不出现在S中。

这样思路的时间复杂度为O(n*m),那么有没有好一点的方法来解决这个问题呢,嘤,当然有,就是众所周知的KMP了。

KMP算法思路:

首先我们设S串(称为主串)为S1S2S3......Sn(S0不存放字符)

设T串(模式串)为T1T2T3......Tm

假设我们对两个串进行匹配,匹配到如下过程:


Si和Tj不匹配了,按照上面的常规思路就是将下边(i-j+1)加上一,再一一匹配了,但是我们的KMP不这样

举个栗子,假设主串为abacabadaea,模式串为abad,我们先模拟一下常规思路的匹配过程:



我们可以看到,在上面的五次匹配过程中,第二次第四次匹配是完全没有必要的,第一次匹配不成功之后直接进行第三次匹配,再进行第五次匹配即可得到结果。

也就是说,主串当前匹配的字符可以不做移动,直接将模式串右移,因为第一次匹配的时候S3和T3已经匹配成功了,而T3又与T1相等所以我们可以将S4直接与T2进行匹配,这样就减少了不必要的匹配次数。

通俗的讲,假设有主串和模式串已经匹配到下面的样子了


要在模式串T中找一个位置k(k<j)来跟si匹配,这时要确保T1...Tk-1==Si-k+1...Si-1

由之前的匹配可知Tj-k+1...Tj-1==Si-k+1...Si-1

所以我们只需要找到一个k,使得T1...Tk-1==Tj-k+1...Tj-1就行,这时匹配就分别从主串的Si、模式串的Tk开始了

令next[j]=k,则next [j]表示模式串中第j个字符与主串中相应字符“失配”时,在模式串中需要重新和主串中该字符进行比较的字符位置。(next被称为前缀表)

所以我们可以得到模式串的定义:

当j=1时,next[j] = 0;

当1<k<j且T1...Tk-1==Tj-k+1...Tj-1时(不为空),next[j] = max{k};

其他情况下,next[j] = 1;

求得next数组后,就可以根据上面的分析来求解匹配情况了。


那么,如何求得next数组呢?

我们先看看模式串abaabcac的next数组的情况:


首先我们可以保证next[1] = 0,假设next[i] = k,该如何求next[i+1]呢?

如果T[i] = T[k]的话,那么next[i+1] = next[i]+1 = k+1;

如果T[i] != T[k], 就继续判断T[i] 是否等于 T[next[k]] 知道找到等于或next[k] = 0为止,如果找到等于,令next[i+1] = next[next[..i..]]+1,反之如果next[next[..i..]] == 0, next[i+1] =1。

即求得next数组。

另外对求next数组还有一个优化问题,如主串为aaabaaaaab,模式串为aaaab,那模式串的next数组如下:


其实按照之前对next数组的定义,next[2] = 1,next[3] = 2, next[4] = 3, next[5] = 4,但是因为T[next[j]] == T[j],就没有与S[i]比较的必要了,所以可以一直往前找next[j]。

以上是我对KMP的理解,如有理解不当之处,欢迎指出。

//去吃个饭,吃完饭给出代码

参考代码:

#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<list>
#include<vector>
#include<iostream>

using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int maxm = 1e4+10;
const int maxn = 1e6+10;
int n,m;
char s[maxn];
char t[maxm];
int next[maxm];
//求前缀表(next数组)
void GetNext()
{
    next[0] = -1;
    int i = 0;
    int j = -1;//next[i]
    while( i < m)
    {
        if( j == -1 || t[i] == t[j])
        {
            i++;
            j++;
            if( t[i] != t[j])
                next[i] = j;
            else
                next[i] = next[j];
        }
        else
            j = next[j];
    }
 //   for( int i = 0; i < m; i++)
 //       printf("%d ",next[i]);
 //   puts("");
}
//求模式串在主串中出现的次数
int KMPCount()
{
    GetNext();
    int ans = 0;
    int i = 0;
    int j = 0;
    while( i < n)
    {
        if( j == -1 || s[i] == t[j])
        {
            i++;
            j++;
        }
        else
            j = next[j];
        if( j == m)
        {
            ans++;
            j = next[j];
        }
    }
    return ans;

}

int main()
{
    int T;
    scanf("%d",&T);
    while( T--)
    {
        scanf("%s%s",t,s);
        n = strlen(s);
        m = strlen(t);
        int ans = KMPCount();
        printf("%d\n",ans);
    }

    return 0;
}

以上

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

字符串之KMP详解 的相关文章

  • C++STL之list容器

    一 list特性 list为带哨兵位双向循环链表 支持任意位置的插入和删除 与 array vector deque 相比 list的移除元素效率更高 最大缺陷是不支持 重载 不支持随机访问 只能通过迭代器进行线性开销的迭代 二 list的
  • 创建窗口

    工作涉及到了opengl的boom的demo 看到了learn opengl中有 所以 从头学起 顺便记录下 链接https learnopengl cn readthedocs io zh latest 01 20Getting 20st
  • GAN,IGBT, MOSFET

    作者 集微网 校对 团团 集微网 爱集微APP 各大主流应用商店均可下载 集微网消息 功率半导体是电子电力装置电能转换与电路控制的核心器件 根据Yole数据 中国已经成为全球最大的功率半导体消费市场 预计至2021年 全球功率器件市场规模将
  • Substance designer 瓦片贴图制作

    瓦片贴图制作 因为最终在unity应用 所以采用BaseColor Metallic Roughness Normal Height贴图的工作流程 对于瓦片的细节上 可以分为 基色 上下两种 污渍 水渍 苔藓 裂痕 如果你研究Substan
  • 使用ffmpeg获取一帧摄像头数据

    最近在研究FFmpeg 比较惊讶的是网上一大堆资料都是在说如何从已有的视频中截取一帧图像 却很少说到如何直接从摄像头中捕获一帧图像 其实我一直有个疑问 就是在Linux下 大家是用什么库来采集摄像头的 opencv 还是自己写v4l2的代码
  • HDOJ1052

    先用最快马比 不行再用最慢马比 都不行 就送最慢马给忘得最快马 include
  • git提交本地仓库至远端

    文章目录 1 创建完项目结构 没有分支 2 在github上新建远程仓库 3 按照上图中红色框中的命令 就可以提交本地 4 提交过程中可能会遇到全局配置文件config 中没有配置用户和邮箱地址的情况 5 git pull push每次都需
  • CSS布局—— float布局和flex布局

    用什么CSS布局 当需要兼容IE9时 使用float布局 当需要兼容IE9且不需要兼容最新浏览器时 使用flex布局 当不需要兼容IE9 需要兼容最新浏览器时 使用grid布局 float布局 父元素 添加clearfix类 清楚浮动bug
  • c++生成uuid

    不引用uuid h生成uuid方式 转自How can I generate UUID in c without using boost library Stack Overflow include
  • vue 时间插件_基于 Vue+Gantt 构建甘特图组件

    昨天给大家推荐了一款H5甘特图插件dhtmlxGantt 今天给大家分享如何在Vue项目中实现甘特图插件 基于dhtmlx gantt插件来实现在vue js项目中创建甘特图 安装依赖 首先需要安装 dhtmlx gantt 模块 npm
  • 对于任何一颗二叉树,若其终端节点数为n0,度为2的结点数为n2,则n0=n2+1

    对于任何一颗二叉树 若其终端节点数为n0 度为2的结点数为n2 则n0 n2 1 设度为0的结点数为n0 度为1的结点数为n1 度为2的结点数为n2 边数为T 第一种方案 由一个节点开始构建二叉树 观察图片 初始状态为n0 1 n1 0 n
  • python数据持久存储:pickle模块的基本使用

    经常遇到在Python程序运行中得到了一些字符串 列表 字典等数据 想要长久的保存下来 方便以后使用 而不是简单的放入内存中关机断电就丢失数据 这个时候Pickle模块就派上用场了 它可以将对象转换为一种可以传输或存储的格式 python的
  • Android入门(一)AndroidStudio下的APP目录结构介绍

    Project Name 工程项目名称 Application Name 当前应用发布以后的名字 例如QQ图标下面的名字是 QQ 就是Application Name Android Studio工程目录 1 gradle和 idea 这两
  • 使用EasyExcel添加Excel数据

    一 导入excel代码 1 pom文件
  • laravel经验分享(2)

    标题laravel经验分享 2 通过一个简单的get请求让新手们了解控制器 模型 数据表 api路由之间的关系 1 控制器创建 php artisan make controller Api newscontroller 创建成功之后 Co
  • 基于Linux安装Docker

    Docker官网 Docker Docs How to build share and run applications Docker Documentation 学习任何技术 一定要参考相应的官网学习 一定要参考官网学习 目录 一 环境准
  • 现场嵌入式设备中的EC20模块如何通过互联网将TCP报文传输到阿里云服务器

    情况说明 现场有几台嵌入式设备 每台设备上有一块EC20模块做为TCP客户端 希望将现场采集的传感器数据通过互联网传输到阿里云服务器 阿里云服务器上面运行一个用C 语言编写的服务器程序 就可以接收现场设备采集的传感器数据 一 阿里云服务器公
  • VC编程实现文本语音转换

    VC编程实现文本语音转换 文本语音 Text to Speech 以下简称TTS 它的作用就是把通过TTS引擎把文本转化为语音输出 本文不是讲述如何建立自己的TTS引擎 而是简单介绍如何运用Microsoft Speech SDK 建立自己
  • dynamo方程怎么写_【简明自控】为什么特征方程如此重要

    简明自动控制 为什么特征方程如此重要 热场视频 自平衡杆 双轴反作用轮倒立摆 哔哩哔哩 干杯 bilibili www bilibili com 顶个棍子 具有主动脚轮的全向移动机器人 哔哩哔哩 干杯 bilibili www bilibi

随机推荐

  • 二叉树的创建、前中后序遍历(递归和非递归)C语言实现

    直接上代码 include
  • LA@方阵相似@相似矩阵的性质@正交相似对角化

    文章目录 方阵相似 引言 相似矩阵定义 相似变换 相似变换矩阵 相似矩阵的矩阵多项式和特征值相同 推论 与对角阵相似的矩阵性质定理 相似矩阵性质 导出性质 相似矩阵的乘方性质 相似矩阵和矩阵多项式 相似对角阵 对角阵多项式的展开 小结 强矩
  • vue3 解决reactive数组对象属性更新问题

    vue3 setup中使用对象数组 const state reactive
  • Python+Selenium-自动化框架登录之验证码识别

    前言 本篇主要记录在项目登录过程中验证码的问题 基于pytesseract和PIL组件实现简单的验证码图片识别 需要自行配置pytesseract PIL环境 目标 获取验证码 自动输入实现登录 一 截取验证码图片信息并保存 访问目标界面
  • Flutter判断当前月份是第几季度、Android判断当前月份是第几季度 、根据月份判断季度方法

    一年有12个月 分为四个季度 怎样判断当前月份是第几个季度呢 方法一 if else 判断 1 flutter 当前月份 int currentMonth DateTime now month 季度 int quarter if curre
  • SpringBoot + MyBatisPlus + MySQL8 实现树形结构查询

    场景 今天在实现权限功能模块时 需要将查询的权限数据 以树形结构的方式返回给前端 功能实现 第一步 权限表结构定义及其功能演示数据 DROP TABLE IF EXISTS baoan privilege CREATE TABLE baoa
  • 3_Docker 常用命令

    进程命令 启动docker服务 systemctl start docker 停止docker服务 systemctl stop docker 重启docker服务 systemctl restart docker 查看docker服务状态
  • 手把手教你 在linux上安装kafka

    目录 1 准备服务器 2 选一台服务器配置kafka安装包 2 1 下载安装包 2 2 解压安装包 2 3 修改配置文件 3 分发安装包到其他机器 4 修改每台机器的broker id 5 配置环境变量 6 启停kafka服务 6 1 启动
  • Linux之RedHat 7 图形界面版安装(转载)

    linuxLinux之RedHat 7 图形界面版安装的详细教程 点击跳转 转载 https blog csdn net star in shy article details 82590241
  • 进程控制块和状态——随堂笔记

    1 PCB 描述进程的数据结构 当一个进程创建以后交给操作系统管理 管理的时候要对进程的属性进行描述 1 进程的描述信息 进程的基本信息pid给每个进程的编号 名字 2 处理器状态信息 在进程执行过程中使用的处理器的各种寄存器的信息 原因
  • Linux下的时间(ZZ)

    1 Linux下的时间 1 1 Linux下的时间系统 1 2 Linux下与时间有关的数据结构 2 获得当前时间 3 延时 4 定时器 4 1 alarm 4 2 setitimer 1 Linux下的时间1 1 Linux下的时间系统
  • Linux CentOS 巡检脚本

    系统巡检脚本 有常用的检查模块 如硬盘 内存 进程等 安全性检查等 1 巡查脚本 代码如下 示例 xunjian sh bin bash 系统状态 host while do clear echo e 当前在查看 e 1 31m 主机状态信
  • 永洪科技入选“2023大数据优秀服务商”

    8月23日 2023大数据优秀服务商 发布 永洪科技入选 此次评选由DBC CIS CIW eNet研究院牵头组织 旨在遴选大数据产业各细分赛道具有代表性与创新力的企业 组织 并展现其独特价值 重点考量技术实力 业内口碑 成长性 品牌力以及
  • LeetCode 5910. 检查两个字符串是否几乎相等

    如果两个字符串 word1 和 word2 中从 a 到 z 每一个字母出现频率之差都 不超过 3 那么我们称这两个字符串 word1 和 word2 几乎相等 给你两个长度都为 n 的字符串 word1 和 word2 如果 word1
  • Vue项目封装div拖动组件,实现div拖拽

    场景 在pc端项目中会碰到弹框后多个页面重叠的场景 类似于电脑打开多个文件夹 这时想要同时完整的展示两个页面的内容 就可以拖动页面 改变位置 很多教程都是使用自定义方法在单个组件中使用 本文带大家在Vue项目中封装一个拖拽div的方法 注册
  • JavaScript 弹窗

    JavaScript弹窗是Web开发中常见的交互方式之一 弹窗可以为用户提供提示 警告或者输入框等交互方式 让用户在使用网站或应用时更加便捷 在本文中 我们将讨论JavaScript弹窗的作用 类型和用途 JavaScript弹窗的作用 J
  • JVM的核心内容

    1 JVM对于java程序员的重要性可以用一下两句话来概述 1 1 关于任何java的技术问题都可以追溯到java虚拟机里面去 1 2 一个Java程序员水平的高低就看你对Java虚拟机这个东西有多了解 2 了解JVM需要先理解jdk与jr
  • 华为某高管工资曝光:每月高达27万,众网友表示长了见识

    如果说一个人工资每个月好几万 估计很多网友都会认为很高了 能拿到这么高薪资的人肯定是非常优秀和有能力的人 近日 一名在某企业从事招聘工作的网友在网上曝光了一条内容 其称在招聘简历中 无意发现了一份华为高管的简历 其级别是21级 月工资高达2
  • 利用Fiddler 解SSL加密 数据包

    在开发互联网应用的过程中 常常会设立或利用网络接口 为了调试对网络接口的使用 往往需要查看流入和流出网络接口的网络流量或数据包 抓包工具 就是一类用于记录通过网络接口的数据的工具 我们知道 网络协议是分层设计的 OSI模型将网络协议分为了7
  • 字符串之KMP详解

    昨晚梳理了一下KMP的过程 感觉印象深刻了不少 在此写下博客加深印象 同时也希望能和大家交流 KMP这个名字来源于其三个创始人名字首字母 主要用于解决字符串的匹配问题 字符串的匹配问题 假设有两个字符串S和T 问串T是否出现在串S中 串T在