当前位置: 首页 > news >正文

【算法】KMP-快速文本匹配

文章目录

    • 一、KMP算法说明
    • 二、详细实现
      • 1. next数组定义
      • 2. 使用next加速匹配
      • 3. next数组如何快速生成
      • 4. 时间复杂度O(m+n)的证明
        • a) next生成的时间复杂度
        • b) 匹配过程时间复杂度
    • 三、例题
      • 1. [leetcode#572](https://leetcode.cn/problems/subtree-of-another-tree/description/)
      • 2. [leetcode#1367](https://leetcode.cn/problems/linked-list-in-binary-tree/description/)

一、KMP算法说明

要判断s1字符串是否包含s2字符串,如果包含返回s1中包含s2的最左开头位置,不包含返回-1

暴力方法就是s1的每个位置都做开头,然后去匹配s2整体,时间复杂度O(n*m),其中n为s1长度,m为s2长度

KMP算法可以做到时间复杂度O(n+m)

二、详细实现

1. next数组定义

字符串s的next数组为int数组,长度等于s的长度。next[i]表示在s中下标i之前子串的前缀和后缀的最大匹配长度(不包含整体)

以字符串"aabaabs"为例

// i=0,规定next[0]为-1
// i=1,由于s[1]之前只有a,除去整体,前缀和后缀只能是空,所以规定next[1]=0
// i=2, "aa",前缀"a",后缀"a",最大匹配长度1,next[2]=1
// i=3, "aab",没有可以匹配的前缀和后缀,next[3]=0
// i=4, "aaba", 前缀"a", 后缀"a", next[4]=1
// i=5, "aabaa", 前缀"aa", 后缀"aa", next[5]=2
// i=6, "aabaab", 前缀"aab", 后缀"aab", next[6]=3
// 扩充的next是可以多计算一位的
// i=7, "aabaabs",没有可以匹配的前缀和后缀,next[7]=0

2. 使用next加速匹配

func kmp(s1, s2 string) int {if len(s1) < len(s2) {return -1}next := nextArr(s2)x, y := 0, 0for x < len(s1) && y < len(s2) {if s1[x] == s2[y] {x++y++} else if y > 0 {y = next[y]} else {x++}}if y == len(s2) {return x - y} else {return -1}
}

3. next数组如何快速生成

func nextArr(s string) []int {if len(s) <= 1 {return []int{-1}}next := make([]int, len(s))next[0], next[1] = -1, 0cp := 0for i := 2; i < len(s); {if s[i-1] == s[cp] {cp++next[i] = cpi++} else if cp > 0 {cp = next[cp]} else {next[i] = 0i++}}return next
}

4. 时间复杂度O(m+n)的证明

a) next生成的时间复杂度
// for循环中我们关注i和i-cp
// i的范围是2~m
// i-cp的范围是0~m
// 分支1:i变大, i-cp不变
// 分支2:i-cp变大
// 分支3:i变大,i-cp变大
// 因此时间复杂度O(m)
b) 匹配过程时间复杂度
// for循环中关注x和x-y
// ...
// 同理时间复杂度O(n)

三、例题

1. leetcode#572

image-20240328005922263

// 思路:将两棵树都序列化为sRoot和sSubRoot,然后判断sSubRoot是否为sRoot的子串func isSubtree(root *TreeNode, subRoot *TreeNode) bool {const nullVal = 1e4 + 1var s1, s2 []ints1 = encode(root, make([]int, 0), nullVal)s2 = encode(subRoot, make([]int, 0), nullVal)return kmp2(s1, s2) >= 0
}
func encode(root *TreeNode, list []int, nullVal int) []int {if root == nil {list = append(list, nullVal)return list}list = append(list, root.Val)list = encode(root.Left, list, nullVal)list = encode(root.Right, list, nullVal)return list
}
func kmp2(s1, s2 []int) int {if len(s1) < len(s2) {return -1}next := nextArrInt(s2)x, y := 0, 0for x < len(s1) && y < len(s2) {if s1[x] == s2[y] {x++y++} else if y > 0 {y = next[y]} else {x++}}if y == len(s2) {return x - y} else {return -1}
}
func nextArrInt(s []int) []int {if len(s) <= 1 {return []int{-1}}next := make([]int, len(s))next[0], next[1] = -1, 0cp := 0for i := 2; i < len(s); {if s[i-1] == s[cp] {cp++next[i] = cpi++} else if cp > 0 {cp = next[cp]} else {next[i] = 0i++}}return next
}

2. leetcode#1367

image-20240328010252351

func isSubPath(head *ListNode, root *TreeNode) bool {if head == nil {return true}if root == nil {return false}list := make([]int, 0)for head != nil {list = append(list, head.Val)head = head.Next}next := nextArrInt(list)return find(root, list, next, 0)
}func find(cur *TreeNode, list []int, next []int, index int) bool {if index == len(list) {return true}if cur == nil {return false}for index >= 0 && cur.Val != list[index] {index = next[index]}// index=-1 => index=0// 匹配 => index+1index++return find(cur.Left, list, next, index) || find(cur.Right, list, next, index)
}

相关文章:

【算法】KMP-快速文本匹配

文章目录 一、KMP算法说明二、详细实现1. next数组定义2. 使用next加速匹配3. next数组如何快速生成4. 时间复杂度O(mn)的证明a) next生成的时间复杂度b) 匹配过程时间复杂度 三、例题1. [leetcode#572](https://leetcode.cn/problems/subtree-of-another-tree/description/)2.…...

多维数组和交错数组笔记

1.) 关于数据的几个概念&#xff1a; Rank&#xff0c;即数组的维数&#xff0c;其值是数组类型的方括号之间逗号个数加上1。 Demo&#xff1a;利用一维数组显示斐波那契数列F(n) F(n-1) F(n-2) (n >2 ),每行显示5项,20项. static void Main(string[] args){int[] F n…...

Python(django)之单一接口展示功能前端开发

1、代码 建立apis_manage.html 代码如下&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>测试平台</title> </head> <body role"document"> <nav c…...

【大模型】非常好用的大语言模型推理框架 bigdl-llm,现改名为 ipex-llm

非常好用的大语言模型推理框架 bigdl-llm&#xff0c;现改名为 ipex-llm bigdl-llmgithub地址环境安装依赖下载测试模型加载和优化预训练模型使用优化后的模型构建一个聊天应用 bigdl-llm IPEX-LLM is a PyTorch library for running LLM on Intel CPU and GPU (e.g., local P…...

Kubernetes示例yaml:3. service-statefulset.yaml

service-statefulset.yaml 示例 apiVersion: apps/v1 kind: statefulset metadata:...... spec:......volumeMounts:- name: pvcmountPath: /var/lib/arangodb3VolumeClaimTemplates:- metadata:name: pvcspec:accessModes: [ "ReadWriteOnce" ]storangeClassName: …...

Windows平台cmake编译QT源码库,使用VScode开发QT

不愿意安装庞大的QT开发IDE&#xff0c;可以编译QT源码库。 下载源码可以用国内镜像&#xff0c;如清华大学的&#xff1a;Index of /qt/archive/qt/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 我用的是 6.5.3&#xff0c;进去之后&#xff0c;不要下载整个源…...

腾讯云轻量8核16G18M服务器多少钱一年?

腾讯云轻量8核16G18M服务器多少钱一年&#xff1f;优惠价格4224元15个月&#xff0c;买一年送3个月。配置为轻量应用服务器、16核32G28M、28M带宽、6000GB月流量、上海/广州/北京、380GB SSD云硬盘。 腾讯云服务器有两个活动&#xff0c;一个是官方的主会场入口&#xff0c;还…...

二分练习题——123

123 二分等差数列求和前缀和数组 题目分析 连续一段的和我们想到了前缀和&#xff0c;但是这里的l和r的范围为1e12&#xff0c;明显不能用O(n)的时间复杂度去求前缀和。那么我们开始观察序列的特点&#xff0c;可以按照等差数列对序列进行分块。如上图&#xff0c;在求前10个…...

淘宝详情数据采集(商品上货,数据分析,属性详情,价格监控),海量数据值得get

淘宝详情数据采集涉及多个环节&#xff0c;包括商品上货、数据分析、属性详情以及价格监控等。在采集这些数据时&#xff0c;尤其是面对海量数据时&#xff0c;需要采取有效的方法和技术来确保数据的准确性和完整性。以下是一些关于淘宝详情数据采集的建议&#xff1a; 请求示…...

Django之Web应用架构模式

一、Web应用架构模式 在开发Web应用中,有两种模式 1.1、前后端不分离 在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示。前端与后端的耦合度很高 1.2、前后端分离 在前后端分离的应用模式中,后端仅返…...

GPT提示词分享 —— 口播脚本

可用于撰写视频、直播、播客、分镜头和其他口语内容的脚本。 提示词&#x1f447; 请以人的口吻&#xff0c;采用缩略语、成语、过渡短语、感叹词、悬垂修饰语和口语化语言&#xff0c;避免重复短语和不自然的句子结构&#xff0c;撰写一篇关于 [主题] 的文章。 GPT3.5&#…...

笔记本作为其他主机显示屏(HDMI采集器)

前言&#xff1a; 我打算打笔记本作为显示屏来用&#xff0c;连上工控机&#xff0c;这不是贼方便吗 操作&#xff1a; 一、必需品 HDMI采集器一个 可以去绿联买一个&#xff0c;便宜的就行&#xff0c;我的大概就长这样 win10下载 PotPlayer 软件 下载链接&#xff1a;h…...

02.percona Toolkit工具pt-archiver命令实践

1.命令作用 Percona Toolkit有的32个命令&#xff0c;可以分为7大类 工具类别 工具命令 工具作用 备注 开发类 pt-duplicate-key-checker 列出并删除重复的索引和外键 pt-online-schema-change 在线修改表结构 pt-query-advisor 分析查询语句&#xff0c;并给出建议&#x…...

【天狼启航者】研究计划

“造车”&#xff0c;预计在4月中旬展开&#xff08;嵌入式蓝桥杯比赛结束后&#xff09;&#xff0c;这里先计划一下&#xff0c;不断更新。 基本要求&#xff1a; 使用STM32F407系列芯片&#xff0c;使用FreeRTOS系统。 驱动程序必须要有强大的可移植性、模块化、低耦合、简…...

面试题 之 webpack

1.说说你对webpack理解&#xff1f;解决什么问题&#xff1f; Webpack 是实现前端项目的模块化&#xff0c;用于现代 JavaScript 应用程序的静态模块打包工具&#xff0c;被webpack 直接引用的资源打包进 bunde.js的资源&#xff0c;当webpack 处理应用程序时,它会在内部构建一…...

【机器学习之旅】概念启程、步骤前行、分类掌握与实践落地

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…...

外星人m18R2国行中文版原厂预装23H2原装Win11系统恢复带F12恢复重置

戴尔外星人m18R2国行中文版原厂预装23H2系统恢复安装 远程恢复安装&#xff1a;https://pan.baidu.com/s/166gtt2okmMmuPUL1Fo3Gpg?pwdm64f 提取码:m64f 1.自带原厂预装系统各驱动&#xff0c;主题&#xff0c;Logo,Office带所有Alienware主题壁纸、Alienware软件驱动 2.带…...

libVLC 视频抓图

Windows操作系统提供了多种便捷的截图方式&#xff0c;常见的有以下几种&#xff1a; 全屏截图&#xff1a;通过按下PrtSc键&#xff08;Print Screen&#xff09;&#xff0c;可以截取整个屏幕的内容。截取的图像会保存在剪贴板中&#xff0c;可以通过CtrlV粘贴到图片编辑工具…...

Docker搭建LNMP环境实战(06):Docker及Docker-compose常用命令

Docker搭建LNMP环境实战&#xff08;06&#xff09;&#xff1a;Docker及Docker-compose常用命令 此处列举了docker及docker-compose的常用命令&#xff0c;一方面可以做个了解&#xff0c;另一方面可以在需要的时候进行查阅。不一定要强行记忆&#xff0c;用多了就熟悉了。 1、…...

ClickHouse10-ClickHouse中Kafka表引擎

Kafka表引擎也是一种常见的表引擎&#xff0c;在很多大数据量的场景下&#xff0c;会从源通过Kafka将数据输送到ClickHouse&#xff0c;Kafka作为输送的方式&#xff0c;ClickHouse作为存储引擎与查询引擎&#xff0c;大数据量的数据可以得到快速的、高压缩的存储。 Kafka大家…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…...

用js实现常见排序算法

以下是几种常见排序算法的 JS实现&#xff0c;包括选择排序、冒泡排序、插入排序、快速排序和归并排序&#xff0c;以及每种算法的特点和复杂度分析 1. 选择排序&#xff08;Selection Sort&#xff09; 核心思想&#xff1a;每次从未排序部分选择最小元素&#xff0c;与未排…...