重生之我在 CSDN 学习 KMP 算法
深入理解 KMP 算法:高效字符串匹配的利器
一、KMP 算法的由来及其解决的问题
在计算机科学领域,字符串处理是一项极为常见且基础的任务。其中,字符串匹配问题更是频繁出现,例如在文本编辑器中查找特定单词、在生物信息学中搜索 DNA 序列模式等。早期,人们普遍采用朴素的字符串匹配算法,该算法简单直观,但在面对长字符串时效率低下。正是在这样的背景下,1977 年,Donald E. Knuth、Vaughan Pratt 和 James H. Morris 共同提出了 KMP 算法,旨在更高效地解决字符串匹配问题,从此开启了字符串匹配算法优化的新篇章。
KMP 算法主要解决的是在一个主字符串(text)中查找一个模式字符串(pattern)出现的位置。简单来说,给定一个长度为 n 的主字符串 text 和一个长度为 m 的模式字符串 pattern(其中 m <= n),需要找出 pattern 在 text 中首次出现的起始索引。朴素字符串匹配算法的时间复杂度为 O (n * m),在最坏情况下,对于每个主字符串中的字符位置,都需要对模式字符串进行完整匹配,导致大量不必要的重复比较。而 KMP 算法通过巧妙利用已经匹配的部分信息,避免了重复匹配,将时间复杂度降低到 O (n + m),大大提高了字符串匹配的效率。下面我们来介绍 KMP 算法的流程。
二、算法流程
2.1 前缀表
前缀表记录了模式字符串中每个前缀子串的最长相等前缀和后缀的长度。对于模式字符串 pattern,设其长度为 m,前缀表是一个长度为 m 的数组,记为 next。next[i] 表示 pattern 的前 i + 1 个字符组成的子串中,最长相等前缀和后缀的长度(不包括整个子串本身)。例如,对于模式字符串 “aabaaf”,其前缀表为 [0, 1, 0, 1, 2, 0]。当 i = 0 时,子串为 “a”,没有相等的前缀和后缀,所以 next[0] = 0;当 i = 1 时,子串为 “aa”,有相等的前缀和后缀"a",next[1] = 0;当 i = 2 时,子串为 “aab”,没有相等的前后缀,所以 next[2] = 0;同理,当 i = 3 时,子串为"aaba",所以 next[3] = 1;当 i = 4时,next[4] = 2;当 i = 5 时,next[5] = 0。
- 构建过程
- 初始化:设模式字符串 pattern 的长度为 m,创建一个长度为 m 的数组 next,初始时 next[0] = 0,因为单个字符没有前后缀。
- 遍历计算:设两个指针,i 指向后缀末尾(从1开始),j 指向前缀末尾(初始为0)。在遍历过程中,比较 pattern[i] 和 pattern[j]。
- 如果 pattern[i] == pattern[j],说明找到了一个更长的相等前缀和后缀,j 增加 1,然后将 j 赋值给 next[i],即 next[i] = j,同时 i 也增加 1,继续下一个位置的计算。
- 如果 pattern[i] != pattern[j],且 j > 0,说明当前位置无法形成更长的相等前缀和后缀,此时需要回溯 j,令 j = next[j - 1],继续比较 pattern[i] 和 pattern[j]。这是因为之前已经知道了长度为 j - 1 的前缀的最长相等前缀和后缀长度,通过回溯可以尝试找到一个更短的前缀,使得 pattern[i] 能够与该前缀的下一个字符匹配。
- 如果 pattern [i] != pattern [j] 且 j == 0,说明从开头到当前位置 i 都没有相等的前缀和后缀,此时 next[i] = 0,i 增加 1,继续下一个位置的计算。
2.2 字符串匹配过程
- 匹配开始:设主字符串 text 的长度为 n,模式字符串 pattern 的长度为 m。初始化两个指针,i 用于遍历主字符串 text(从 0 开始),j 用于遍历模式字符串 pattern(从 0 开始)。
- 字符比较:在匹配过程中,不断比较 text [i] 和 pattern [j]。
- 如果 text[i] == pattern[j],说明当前字符匹配成功,i 和 j 都增加 1,继续比较下一个字符。
- 如果 text[i] != pattern[j],此时不能简单地将 i 回溯到上次匹配的起始位置重新开始比较,而是要利用前缀表进行优化。令 j = next[j - 1],这意味着将模式字符串向右移动,使得已经匹配的部分尽可能多地利用之前的匹配信息,减少不必要的重复比较。
- 匹配成功或失败判断:当 j 等于模式字符串的长度 m 时,说明模式字符串在主字符串中找到了匹配,返回当前 i - j 的值,即为模式字符串在主字符串中首次出现的起始索引。如果 i 遍历完主字符串 text,j 仍未达到 m,说明模式字符串在主字符串中不存在匹配,返回 -1。
三、举个栗子
假设主字符串 text = “abababca”,模式字符串 pattern = “ababca”。
3.1 构建前缀表
- 初始化 next 数组,长度为 6,next[0] = 0,并令 j = 0。
- 当 i = 1 时,pattern[1] = ‘b’,pattern[0] = ‘a’,不相等,next[1] = 0。
- 当 i = 2 时,pattern[2] = ‘a’,pattern[0] = ‘a’,相等,j 从 0 变为 1,next[2] = 1。
- 当 i = 3 时,pattern[3] = ‘b’,pattern[1] = ‘b’,相等,j 从 1 变为 2,next[3] = 2。
- 当 i = 4 时,pattern[4] = ‘c’,pattern[2] = ‘a’,不相等,j 回溯,j = next[2 - 1] = next[1] = 0。因为pattern[4]与pattern[0]不相等,所以next[4] = 0。
- 当 i = 5 时,pattern[5] = ‘a’,pattern[0] = ‘a’,相等,j 从 0 变为 1,next[5] = 1。所以前缀表next = [0, 0, 1, 2, 0, 1]。
3.2 字符串匹配过程
- 初始化 i = 0,j = 0。
- 比较 text[0] 和 pattern[0],都为 ‘a’,匹配成功,i = 1,j = 1。
- 比较 text[1] 和 pattern[1],都为 ‘b’,匹配成功,i = 2,j = 2。
- 比较 text[2] 和 pattern[2],都为 ‘a’,匹配成功,i = 3,j = 3。
- 比较 text[3] 和 pattern[3],都为 ‘b’,匹配成功,i = 4,j = 4。
- 比较 text[4] 和 pattern[4],text[4]为’a’,pattern[4]为’c’,不匹配,j 回溯,j = next[4 - 1] = next[3] = 2。
- 继续比较 text[4] 和 pattern[2],text[4]为’a’,pattern[2]为’a’,匹配成功,i = 5,j = 3。
- 比较 text[5] 和 pattern[3],text[5]为’b’,pattern[3]为’b’,匹配成功,i = 6,j = 4。
- 比较 text[6] 和 pattern[4],text[6]为’c’,pattern[4]为’c’,匹配成功,i = 7,j = 5。
- 比较 text[7] 和 pattern[5],text[7]为’a’,pattern[5]为’a’,匹配成功,j 达到模式字符串长度 m = 6,此时返回 i - j + 1 = 7 - 6 + 1 = 2,说明模式字符串在主字符串中首次出现的起始索引为 2。
四、代码实现
class Solution {public int match(String text, String pattern) {if (pattern.length() == 0) return 0;int[] next = new int[pattern.length()];getNext(next, pattern);int j = 0;for (int i = 0; i < text.length(); i++) {while (j > 0 && pattern.charAt(j) != text.charAt(i)) j = next[j - 1];if (pattern.charAt(j) == text.charAt(i)) j++;if (j == pattern.length()) return i - pattern.length() + 1;}return -1;}private void getNext(int[] next, String s) {int j = 0;next[0] = 0;for (int i = 1; i < s.length(); i++) {while (j > 0 && s.charAt(j) != s.charAt(i)) j = next[j - 1];if (s.charAt(j) == s.charAt(i)) j++;next[i] = j; }}
}
相关文章:
重生之我在 CSDN 学习 KMP 算法
深入理解 KMP 算法:高效字符串匹配的利器 一、KMP 算法的由来及其解决的问题 在计算机科学领域,字符串处理是一项极为常见且基础的任务。其中,字符串匹配问题更是频繁出现,例如在文本编辑器中查找特定单词、在生物信息学中搜索 D…...
文献学习——考虑混合储能系统选择的基于改进蜂群算法的热电联产微网多目标经济优化调度
摘要:在考虑混合储能系统模型选择的基础上,基于改进的人工蜂群算法(ABC),建立了冷热电联产微电网经济优化的多目标调度模型。为了对以往研究中的单目标模型进行升级,将模型的优化目标设定为微电网的日发电调…...
GPTQ - 生成式预训练 Transformer 的精确训练后压缩
GPTQ - 生成式预训练 Transformer 的精确训练后压缩 flyfish 曾经是 https://github.com/AutoGPTQ/AutoGPTQ 现在是https://github.com/ModelCloud/GPTQModel 对应论文是 《Accurate Post-Training Quantization for Generative Pre-trained Transformers》 生成式预训练Tr…...
nnMamba:基于状态空间模型的3D生物医学图像分割、分类和地标检测
摘要 本文提出了一种基于状态空间模型(SSMs)的创新架构——nnMamba,用于解决3D生物医学图像分割、分类及地标检测任务中的长距离依赖建模难题。nnMamba结合了卷积神经网络(CNN)的局部特征提取能力与SSMs的全局上下文建…...
安科瑞新能源充电桩解决方案:驱动绿色未来,赋能智慧能源
安科瑞顾强 引言 在“双碳”目标与新能源汽车产业高速发展的双重驱动下,充电基础设施正成为能源转型的核心环节。安科瑞电气股份有限公司凭借在电力监控与能效管理领域20余年的技术积淀,推出新一代新能源充电桩解决方案,以智能化、高兼容性…...
使用开源OPUS-MT模型进行文本翻译(python)
1. 环境准备 pip install transformers 2. 下载机器翻译模型: 2.1 代码从hugging face平台下载 from transformers import MarianMTModel, MarianTokenizer# 指定模型名称 model_name "Helsinki-NLP/opus-mt-zh-en" # 中译英模型# 下载并保存分词器到…...
通过 Docker openssl 容器生成生成Nginx证书文件
使用 alpine/openssl 镜像生成证书 1. 拉取容器 [rootlocalhost ~]# docker run --rm alpine/openssl version OpenSSL 3.3.3 11 Feb 2025 (Library: OpenSSL 3.3.3 11 Feb 2025)2. 运行 alpine/openssl 生成证书(Nginx) # 生成1个.key私钥文件&#…...
Elastic如何获取当前系统时间
文章目录 1. 使用 _ingest.timestamp 在 Ingest Pipeline 中获取当前时间2. 使用 Painless Script 获取当前时间3. 使用 now 关键字在查询中获取当前时间4. 使用 date 类型字段的默认值5. 使用 Kibana 的 Dev Tools 查看当前时间6. 使用 date 聚合获取当前时间7. 使用 Elastics…...
MLT媒体程序框架03:滤镜——loudness
EBU R.128协议 引用链接 EBU的全称为European Broadcasting Union ,既欧洲广播联盟,为欧洲与北非各广播业者(包含广播电台与电视台)的合作组织,成立于1950年2月12日,有五十多个正式加盟国,总部位于瑞士日内瓦,目前中国…...
jenkins配置连接k8s集群
jenkins配置连接k8s集群 前言 我这边jenkins是在一个服务器里面,k8s集群在其他服务器,实现连接 首先jenkins下载有k8s插件 进入配置页面 获取k8s-api-server地址 对应k8s服务器执行 kubectl config view --minify -o jsonpath{.clusters[0].cluste…...
如何选择缓存模式?
如何选择缓存模式 当一个系统引入缓存后,最大的挑战之一便是如何确保缓存与后端数据库的一致性。目前,常见的解决方案主要有Cache Aside、Read/Write Throught和Write Back这三种缓存更新策略。 Read/Write Throught策略 读操作方面,如果缓…...
机器学习常见面试题
常见基模型 1. 线性模型(Linear Models) 特点:通过线性组合特征进行预测,适合处理线性关系。常见类型: 线性回归(Linear Regression)逻辑回归(Logistic Regression)岭回…...
网络安全配置截图 网络安全i
网络安全概念及规范 1.网络安全定义 网络安全的概述和发展历史 网络安全 广义的网络安全:Cyber Security(网络空间安全) 网络空间有独立且相互依存的信息基础设施和网络组成,包括互联网、电信网、计算机系统、嵌入式处理器和控…...
k8s概念及k8s集群部署(Centos7)
Centos7部署k8s集群 部署之前,先简单说下k8s是个啥: 一、k8s简介: k8s,全称:kubernetes,它可以看作是一个分布式系统支撑平台。k8s的作用: 1、故障自愈: k8s这个玩意可以监控容器…...
Manus详细介绍,Manus核心能力介绍
文章目录 前言Manus产品定位与核心理念:Manus产品特性与未来体验战略:Manus商业价值与创新指标:Manus技术特点与竞争优势:Manus用户反馈与展望:Manus市场竞争优势与团队战略:Manus深度总结与启发: 前言 这是一篇关于Manus智能体产品的用户体验评价报告,主要介绍了M…...
Apache XTable:在数据湖仓一体中推进数据互作性
Apache XTable 通过以多种开放表格式提供对数据的访问,在增强互作性方面迈出了一大步。移动数据很困难,在过去,这意味着在为数据湖仓一体选择开放表格式时,您被锁定在该选择中。一个令人兴奋的项目当在数据堆栈的这一层引入互作性…...
Java直通车系列14【Spring MVC】(深入学习 Controller 编写)
目录 基本概念 编写 Controller 的步骤和要点 1. 定义 Controller 类 2. 映射请求 3. 处理请求参数 4. 调用业务逻辑 5. 返回响应 场景示例 1. 简单的 Hello World 示例 2. 处理路径变量和请求参数 3. 处理表单提交 4. 处理 JSON 数据 5. 异常处理 基本概念 Cont…...
36-Openwrt wifi命令工具iwconfig、iwinfo、iwpriv、iwlist
增对wifi的调试命令有很多,这边列出我们常用的命令提供参考,方便查看信息定位问题。 1、iwconfig 查看当前 WIFI 的工作信道以及工作带宽模式: root@openwrt:/# iwconfig ra0 ra0 mt7603e ESSID:"openwrt" Mode:Managed Channel:8 Access Point: DC:4B…...
tauri加载网页处理点击a链接默认浏览器打开问题
添加click事件,当点击了a标签,就阻止默认事件,然后自己处理,在自己窗口中打开这个页面。将这个js注入到页面中就可以了 const hookClick (e) > {console.log(hookClick, e)e.preventDefault()const origin e.target.closest…...
openharmony 软总线-设备发现流程
6.1 设备发现流程 6.1.1 Wi-Fi设备发现 6.1.1.1 Wi-Fi设备发现流程 Wi-Fi设备在出厂状态或者恢复出厂状态下,设备上电默认开启SoftAP模式,SoftAP的工作信道在1,6,11中随机选择,SoftAP的Beacon消息中携带的SSID eleme…...
大白话CSS 优先级计算规则的详细推导与示例
大白话CSS 优先级计算规则的详细推导与示例 答题思路 引入概念:先通俗地解释什么是 CSS 优先级,让读者明白为什么要有优先级规则,即当多个 CSS 样式规则作用于同一个元素时,需要确定哪个规则起作用。介绍优先级的分类࿱…...
【GoTeams】-4:为项目引入etcd
本文目录 1. 书接上回2. 引入etcddiscoverystruct{}{} resolverserver 3. 将服务注册到etcd中4. 梳理下etcd调用逻辑 1. 书接上回 本节是为项目引入etcd这个环节,然后我们来看看具体该怎么实现。 首先来谈谈为什么要引入服务发现? 动态服务注册与发现…...
DeepSeek + Kimi:高效制作PPT实战详解
在快节奏的职场环境中,制作高质量的PPT已成为许多人的日常任务。然而,从零开始构思、设计、撰写并优化一份精美的PPT往往耗时费力。幸运的是,AI技术的飞速发展为我们提供了全新的解决方案。本文将详细介绍如何利用DeepSeek与Kimi智能助手的高…...
计算机基础:二进制基础06,用八进制来计数
专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏,故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 (一)WIn32 专栏导航 上一篇:计算机基础:二进制基础05,八进制简介 回…...
OSCP最新备考攻略:迎接2024改版后的OSCP+认证
OSCP(Offensive Security Certified Professional)是渗透测试领域一块金字招牌,由Offensive Security打造,因其硬核实战和高门槛备受推崇。2024年11月1日,OSCP迎来了一次重量级改版,推出了OSCP认证…...
Jmeter使用介绍
文章目录 前言Jmeter简介安装与配置JDK安装与配置JMeter安装与配置 打开JMeter方式一方式二 设置Jmeter语言为中文方法一(仅一次性)方法二(永久设置成中文) Jmeter文件常用目录 元件与组件元件组件元件的作用域元件的执行顺序第一个案例添加线程组添加 H…...
hooks useModule自定义hooks (二次封装AgGridReact ag-table)自定义表头,自定义表头搜索
场景业务: 多次运用AgGridReact的table 列表 思路: 运用自定义hooks进行二次封装: 通用配置例如:传参的参数,传参的url,需要缓存的key这些键值类 定制化配置例如:需要对table 的一些定制化传…...
Android Studio 配置国内镜像源
Android Studio版本号:2022.1.1 Patch 2 1、配置gradle国内镜像,用腾讯云 镜像源地址:https\://mirrors.cloud.tencent.com/gradle 2、配置Android SDK国内镜像 地址:Index of /AndroidSDK/...
OFA:通过简单的序列到序列学习框架统一架构、任务和模态
【摘要】 摘要总结 本文介绍了一种新的统一框架OFA(One For All),旨在通过一个简单的序列到序列学习框架来实现跨模态和单模态任务的统一预训练。OFA框架支持任务无关性和模态无关性,并能实现任务全面性。OFA统一了包括图像生成、视觉定位、图像字幕、图像分类、语言建模…...
C++11新特性2.空指针nullptr
目录 一.简介 1.基本概念 2.语法 二.使用示例 示例1:初始化指针 示例2:作为函数参数 三.nullptr与NULL的区别 1.类型安全 2.函数重载问题 3.注意事项 一.简介 1.基本概念 nullptr 是一个类型安全的空指针常量,它的类型是 std::nul…...
