数据结构与算法学习笔记----KMP

数据结构与算法学习笔记----KMP

@@ author: 明月清了个风

@@ last edited: 2024.11.24

Acwing 831. KMP字符串

给定一个字符串 S S S,以及一个模式串 P P P,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模式串 P P P在字符串 S S S中多次作为子串出现。

求出模式串 P P P在字符串 S S S中所有出现的位置的起始下标。

输入格式

第一行包含整数 N N N,表示字符串 P P P的长度。

第二行输入字符串 P P P

第三行输入整数 M M M,表示字符串 S S S的长度。

第四行输入字符串 S S S

输出格式

共一行,输出所有出现位置的起始下标(下标从 0 0 0开始计数),整数之间用空格隔开。

数据范围

1 ≤ N ≤ 1 0 5 1 \leq N \leq 10^{5} 1N105,

1 ≤ M ≤ 1 0 6 1 \leq M \leq 10^{6} 1M106

思路

首先考虑暴力做法,两重循环即可完成,伪代码如下:

...  //  原字符串为S,模式串为Pfor(int i = 0; i < n; i ++)  // 循环字符串S{bool flag = false;int temp = i;  // 存这一轮匹配的起始位置for(int j = 0; j < m;)  // 循环模式串P{while(s[i] == p[j] && j < m) i ++, j ++;if(j == m) flag = true; // 将模式串P循环到底说明这轮匹配成功else break;  // 否则表示这一轮匹配失败,直接跳出。}if(flag) cout << temp << ' ';i = temp;  }
...

时间复杂度为:O(n * m)

这里模拟KMP的暴力匹配过程,字符串 S S S P P P中的元素分别用 a i a_{i} ai b i b_{i} bi表示:

  1. 假设目前已经匹配完成的是 a i a_{i} ai b j b_{j} bj,也就是说字符串 S S S中的[1 ~ i]与模式串 P P P中的[1 ~ j]相等,即图中红框中的两部分相等
    在这里插入图片描述

  2. a i + 1 a_{i+1} ai+1 b j + 1 b_{j + 1} bj+1不相等时,此时匹配失败(如图中紫色虚线框中),那么此时需要将模式串 P P P向后移动,暴力做法中应移动一位,若此时字符串 S S S[2 ~ i]项与模式串 P P P[1 ~ j - 1]项能够匹配成功也就意味着,对于模式串 P P P而言,其前 [1 ~ j]项中前缀[1 ~ j - 1]项与后缀[2 ~ j]项是相等的(由一步的图中可以知道字符串 S S S中的[2 ~ i]项等于模式串 P P P中的[2 ~ j]项)
    在这里插入图片描述

那么如果对于模式串而言,若其前 [1 ~ j]项中前缀[1 ~ j - 1]项与后缀[2 ~ j]项不相等,相等的是前缀[1 ~ j - 2]与后缀[3 ~ j],那么就会出现下图的情况:
在这里插入图片描述
当暴力匹配第一步匹配到 a i + 1 a_{i+1} ai+1失败后,试图将模式串向后移动一位重新匹配,但是肯定匹配未到 a i + 1 a_{i+1} ai+1就会失败(因为其前 [1 ~ j]项中前缀[1 ~ j - 1]项与后缀[2 ~ j]项不相等),因此继续向后移动一位,因为此时模式串 P P P中前缀[1 ~ j - 2]与后缀[3 ~ j]相等,因此可以直接继续匹配 a i + 1 a_{i+1} ai+1,图中所示的第二步就是可被优化掉的操作,也就是跳过一定不可能匹配成功的位置。

综上所述可以得出优化暴力做法的思路:针对模式串 P P P预处理出其以第一项为头的所有长度的连续子串的最大的相同前后缀子串。
解释一下这句话:

  1. 因为模式串 P P P需要完整匹配,因此总是需要从第一项开始匹配
  2. 当匹配到某一个位置失败后,因为前面的都已与字符串 S S S匹配成功,且被匹配字符串 S S S不动,那么此时将模式串 P P P向后移动就相当于用模式串 P P P去匹配自己的后缀,那么为了减少匹配次数,假设匹配失败位置是 b i b_{i} bi,那么只要知道模式串 P P P的以第一项 b 1 b_{1} b1为头到 b i − 1 b_{i-1} bi1这个子串(即子串 b 1 ∼ i − 1 b_{1 \sim i-1} b1i1)的最大相同前后缀即可直接继续匹配 b i b_{i} bi,若仍不匹配,继续递归即可。

优化后的KMP算法时间复杂度为O(m + n)

代码

#include <iostream>using namespace std;const int N = 100010, M = 1000010;int n, m;
char s[M], p[N];
int ne[N];int main()
{cin >> n >> p + 1 >> m >> s + 1;for(int i = 2, j = 0; i <= n; i ++){while(j && p[i] != p[j + 1]) j = ne[j];if(p[i] == p[j + 1]) j ++;ne[i] = j;}for(int i = 1, j = 0; i <= m; i ++){while(j && s[i] != p[j + 1]) j = ne[j];if(s[i] == p[j + 1]) j ++;if(j == n){cout << i - n << ' ';j = ne[j];}}return 0;
}

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

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

相关文章

算法基础 - 二分迭代法求解非线性方程

文章目录 1. 基本思想2. 编程实现2.1. 非递归2.2. 递归方案 3. 总结 二分迭代法使用了二分算法思想求解非线性方程式。 下面要求使用二分迭代法求解&#xff1a; 2x3-5x-10 方程式&#xff0c;且要求误差不能大于10e-5。 二分迭代法也只是近似求解算法。 所谓求解&#xff…

家校通小程序实战教程03学生管理

目录 1 创建数据源2 搭建后台功能3 设置主列字段4 批量导入数据5 设置查询条件6 实现查询和重置总结 我们现在已经搭建了班级管理&#xff0c;并且录入了班级口令。之后就是加入班级的功能了。这里分为老师加入班级和学生家长加入班级。 如果是学生家长的话&#xff0c;在加入之…

springboot336社区物资交易互助平台pf(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 社区物资交易互助平台设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff…

python学习——元组

在 Python 中&#xff0c;元组&#xff08;tuple&#xff09;是一种内置的数据类型&#xff0c;用于存储不可变的有序元素集合。以下是关于 Python 元组的一些关键点&#xff1a; 文章目录 定义元组1. 使用圆括号 ()2. 使用 tuple() 函数3. 使用单个元素的元组4. 不使用圆括号…

【C++】7000字介绍map容器和set容器的功能和使用

目录 一、关联式容器和序列式容器 二、键值对,> 三、树形结构的关联式容器 四、set容器&#xff08;key模型&#xff09; 1、文档官网 2、功能介绍&#xff1a; 3、注意事项&#xff1a; 4、基本使用&#xff0c;更多接口可查看官网&#xff1a; &#xff08;1&…

嵌入式C语言技巧15:深入浅出:多线程编程中锁的选择与优化策略

文章目录 导读一、锁机制概览二、实战演练:锁的选择与使用三、代码执行结果与分析四、总结与展望本文是经过严格查阅相关权威文献和资料,形成的专业的可靠的内容。全文数据都有据可依,可回溯。特别申明:数据和资料已获得授权。本文内容,不涉及任何偏颇观点,用中立态度客观…

【K8s】【部署】集群部署

1 主机/服务规划 主机IP主机名节点功能类型服务分布192.168.199.20k8s.master.vip vip虚拟IP192.168.199.21k8s01k8s-MasterKeepalived、HAProxy、Docker192.168.199.22k8s02k8s-MasterKeepalived、HAProxy、Docker192.168.199.23k8s03k8s-NodeDocker192.168.199.24k8s04k8s-N…

【Git】常用命令汇总

目录 一.安装及配置 1.在 Windows 上安装 2.用户信息 3.差异分析工具 二.基础 1.创建仓库 2.提交与修改 三.分支管理 1.创建分支 2.合并分支 四.远程操作 1.管理 Git 仓库中的远程仓库 2.数据的获取与推送 五.标签 1.创建轻量标签和附注标签 2.查看标签和标签信…

AWS海外注册域名是否需要实名认证?

在全球化的互联网环境中&#xff0c;注册域名已成为企业和个人建立在线存在的重要步骤。亚马逊网络服务&#xff08;AWS&#xff09;作为全球领先的云服务提供商&#xff0c;其域名注册服务也备受关注。然而&#xff0c;对于在AWS上注册海外域名是否需要实名认证&#xff0c;许…

【C++进阶篇】像传承家族宝藏一样理解C++继承

文章目录 须知 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…

【大数据测试之:RabbitMQ消息列队测试-发送、接收、持久化、确认、重试、死信队列并处理消息的并发消费、负载均衡、监控等】详细教程---保姆级

RabbitMQ消息列队测试教程 一、环境准备1. 安装 RabbitMQ2. 安装 Python 依赖 二、基本消息队列中间件实现1. 消息发送模块2. 消息接收模块 三、扩展功能1. 消息持久化和队列持久化2. 消息优先级3. 死信队列&#xff08;DLQ&#xff09; 四、并发处理和负载均衡1. 使用 Python …

DAMODEL丹摩|部署FLUX.1+ComfyUI实战教程

本文仅做测评体验&#xff0c;非广告。 文章目录 1. FLUX.1简介2. 实战2. 1 创建资源2. 1 ComfyUI的部署操作2. 3 部署FLUX.1 3. 测试5. 释放资源4. 结语 1. FLUX.1简介 FLUX.1是由黑森林实验室&#xff08;Black Forest Labs&#xff09;开发的开源AI图像生成模型。它拥有12…

具体的技术和工具在县级融媒体建设3.0中有哪些应用?

以下是结合数据来看县级融媒体建设3.0的一些情况&#xff1a; 技术应用方面 大数据&#xff1a;人民网舆情数据中心执行主任董盟君提到&#xff0c;通过大数据分析可让融媒体单位快速关注聚焦点&#xff0c;实现智能策划、智能推送、智能传播&#xff0c;推动媒体传播影响力提…

中兴机顶盒B860AV1.1刷机固件升级和教程「适用4/8G版」

准备工作&#xff1a; TTL 线&#xff08;CH340G 按系统版本找到要对应驱动&#xff09;下载 putty 软件拆开电视盒接好 TTL 线&#xff08;2、5、6 针脚对应GND、RX、TX&#xff09;在资源管理器的端口选项下找到 CH340G&#xff0c;记住端口号&#xff08;如 COM4&#xff0…

论 AI(人工智能)的现状

刚直播完&#xff0c;就写篇文章&#xff0c;说说我对AI的看法。 一直以来&#xff0c;想对AI 有一个总结&#xff0c;现在AI工具层出不穷&#xff0c;但是它的本质上发展还是缓慢&#xff0c;通过其他方式来扩展本身的能力。 我认为的人工智能 只有像钢铁侠与贾维斯以及终结…

volcano k8s 部署

下载volcano-development文件 官网 https://volcano.sh/zh/docs/installation/volcano-development.yaml wget https://raw.githubusercontent.com/volcano-sh/volcano/master/installer/volcano-development.yaml部署volcano 查下需要下载的镜像 grep vc- volcano-develo…

SeggisV1.0 遥感影像分割软件【源代码】讲解

在此基础上进行二次开发&#xff0c;开发自己的软件&#xff0c;例如&#xff1a;【1】无人机及个人私有影像识别【2】离线使用【3】变化监测模型集成【4】个人私有分割模型集成等等&#xff0c;不管是您用来个人学习 还是公司研发需求&#xff0c;都相当合适&#xff0c;包您满…

Dubbo 最基础的 RPC 应用(使用 ZooKeeper)

看国内的一些项目时 Dubbo 这个词经常闪现&#xff0c;一直也不以为然&#xff0c;未作搜索&#xff0c;当然也不知道它是做什么用的。直到最近阅读关于大型网站架构相关的书中反复提到 Dubbo 后&#xff0c;觉得不能再对它视而不见。Google 了一下&#xff0c;它是在阿里巴巴创…

QINQ技术

定义 QINQ即802.1q in 802.1q&#xff0c;因为IEEE802.1Q中定义的Vlan Tag域只有12个比特&#xff0c;仅能表示4096个Vlan&#xff0c;随网络发展被用尽&#xff0c;于是在原有带vlan的数据上再携带一层vlan标签用于扩展vlan数目。一般来说外层vlan是公网&#xff0c;内层是私…

用哪两种方式来实现集合的排序?

集合&#xff08;Set&#xff09;是一种常见的数据结构&#xff0c;用于存储不重复的元素。在某些情况下&#xff0c;我们需要对集合中的元素进行排序。虽然集合本身是无序的&#xff0c;但我们可以将集合转换为其他有序的数据结构&#xff08;如列表&#xff09;来实现排序。 …