字符串匹配算法:暴力匹配、KMP 算法、Boyer-Moore 算法、Rabin-Karp 算法
字符串匹配算法
字符串匹配算法是在一个字符串(称为文本)中查找另一个字符串(称为模式)出现的位置或者是否存在的算法。常见的字符串匹配算法包括暴力匹配、KMP算法、Boyer-Moore算法和Rabin-Karp算法。下面是对这些算法的简要介绍:
暴力匹配(Brute Force)算法:
- 算法原理:暴力匹配算法是最简单的一种字符串匹配算法。它的原理是从文本的每一个可能的位置开始,依次比较文本中的子串与模式串是否匹配。如果匹配成功,则返回匹配的位置;否则,继续尝试下一个位置。
- 时间复杂度:平均情况下为O(m*n),其中m为文本长度,n为模式长度。
- 优点:
- 算法简单易懂,容易实现。
- 不需要额外的预处理步骤。
- 缺点:
- 效率较低,时间复杂度为O(m*n),其中m为文本长度,n为模式长度。
- 对于大规模文本和模式,性能较差。
代码示例:
/*** 暴力匹配算法** @param text 目标文本* @param pattern 匹配模式* @returns 返回匹配模式在目标文本中的起始位置,如果没有找到匹配则返回-1*/
function bruteForce(text, pattern) {const m = text.length;const n = pattern.length;// 遍历文本串,查找模式串for (let i = 0; i <= m - n; i++) {let j = 0;// 逐个比较文本串和模式串的字符while (j < n && text[i + j] === pattern[j]) {j++;}// 如果模式串全部匹配成功if (j === n) {return i; // 返回匹配的起始位置}}// 没有找到匹配return -1; // 没有找到匹配
}// 示例用法
const text = "hello world";
const pattern = "world";
console.log(bruteForce(text, pattern)); // 输出: 6
KMP(Knuth-Morris-Pratt)算法:
- 算法原理:KMP算法通过预处理模式串构建部分匹配表(也称为next数组),然后在匹配过程中根据部分匹配表来移动模式串,避免重复比较已经匹配的部分。
- 时间复杂度:O(m+n),其中m为文本长度,n为模式长度。
- 优点:
- 在大多数情况下,时间复杂度为O(m+n),具有较高的效率。
- 通过部分匹配表避免了不必要的比较,提高了搜索速度。
- 缺点:
- 实现较为复杂,需要构建部分匹配表。
- 在特定情况下,性能可能不如其他算法。
代码示例:
/*** 生成KMP算法中的部分匹配表** @param pattern 待匹配的字符串* @returns 返回部分匹配表*/
function kmpTable(pattern) {// 获取模式串的长度const n = pattern.length;// 初始化表数组,初始值都为0const table = new Array(n).fill(0);// 初始化指针i和jlet i = 1, j = 0;// 当i小于n时,循环执行以下操作while (i < n) {// 如果模式串的第i个字符与第j个字符相等if (pattern[i] === pattern[j]) {// j指针向后移动一位j++;// 将j的值赋给表数组的第i个位置table[i] = j;// i指针向后移动一位i++;// 如果j大于0} else if (j > 0) {// 将j的值更新为表数组的第j-1个位置的值j = table[j - 1];// 如果j等于0} else {// i指针向后移动一位i++;}}// 返回表数组return table;
}/*** 使用KMP算法在文本中搜索模式串** @param text 文本* @param pattern 模式串* @returns 返回模式串在文本中的起始位置,如果未找到则返回-1*/
function kmpSearch(text, pattern) {const m = text.length;const n = pattern.length;if (n === 0) {return 0;}// 生成部分匹配表const table = kmpTable(pattern);let i = 0, j = 0;while (i < m) {// 如果当前字符匹配成功if (text[i] === pattern[j]) {i++;j++;// 如果已经匹配完整个模式串if (j === n) {return i - n; // 返回匹配的起始位置}// 如果当前字符匹配失败,且模式串的下一个字符不是第一个字符} else if (j > 0) {// 根据部分匹配表进行跳转j = table[j - 1];// 如果当前字符匹配失败,且模式串的下一个字符是第一个字符} else {i++;}}// 没有找到匹配return -1; // 没有找到匹配
}// 示例用法
const text = "hello world";
const pattern = "world";
console.log(kmpSearch(text, pattern)); // 输出: 6
Boyer-Moore算法:
- 算法原理:Boyer-Moore算法是一种启发式的字符串匹配算法,它利用了模式串中的信息来尽可能地跳过不必要的比较。主要有两种启发式规则:坏字符规则和好后缀规则。
- 时间复杂度:最坏情况下为O(m*n),但平均情况下具有较高的效率。
- 优点:
- 在实际应用中通常具有较高的效率,尤其是在模式串较长、字符集较大的情况下。
- 利用了启发式规则,能够快速跳过不匹配的位置,减少比较次数。
- 缺点:
- 实现相对复杂,需要理解和实现坏字符规则和好后缀规则。
- 在某些情况下,性能可能不如其他算法。
代码示例:
/*** Boyer-Moore 字符串匹配算法** @param text 待匹配的文本* @param pattern 待匹配的模式* @returns 返回匹配到的起始位置,若未找到则返回-1*/
function boyerMoore(text, pattern) {const m = text.length;const n = pattern.length;if (n === 0) {return 0;}// 构建字符最后出现位置的映射const skip = {};for (let i = 0; i < n - 1; i++) {skip[pattern[i]] = n - i - 1;}skip[pattern[n - 1]] = n;let i = 0;while (i <= m - n) {let j = n - 1;// 从后往前匹配文本和模式while (j >= 0 && text[i + j] === pattern[j]) {j--;}if (j === -1) {return i; // 如果全部匹配成功,返回匹配的起始位置}// 根据字符最后出现位置的映射计算下一个匹配位置i += skip[text[i + n - 1]] || n;}return -1; // 没有找到匹配
}// 示例用法
const text = "hello world";
const pattern = "world";
console.log(boyerMoore(text, pattern)); // 输出: 6
Rabin-Karp算法:
- 算法原理:Rabin-Karp算法利用哈希函数来对模式串和文本中的子串进行哈希计算,然后比较哈希值来确定是否匹配。它适用于在一段文本中搜索多个不同的模式串。
- 时间复杂度:平均情况下为O(m+n),其中m为文本长度,n为模式长度。
- 优点:
- 在多个模式串匹配和字符串搜索中具有良好的性能。
- 利用哈希函数实现了快速的模式匹配。
- 缺点:
- 对于哈希冲突的处理和哈希函数的设计需要注意,影响算法的准确性和性能。
- 在某些情况下,哈希函数的计算可能会造成额外的开销。
代码示例:
/*** Rabin-Karp 字符串匹配算法** @param text 文本字符串* @param pattern 模式字符串* @returns 返回模式字符串在文本字符串中首次出现的位置,若未找到则返回 -1*/
function rabinKarp(text, pattern) {const m = text.length;const n = pattern.length;if (n === 0) {return 0;}// 字符集大小const d = 256; // 字符集大小// 一个质数const q = 101; // 一个质数let p = 0, t = 0, h = 1;// 计算哈希值的基础值for (let i = 0; i < n - 1; i++) {h = (h * d) % q;}// 计算模式串和文本串的哈希值for (let i = 0; i < n; i++) {p = (d * p + pattern.charCodeAt(i)) % q;t = (d * t + text.charCodeAt(i)) % q;}// 遍历文本串,查找匹配for (let i = 0; i <= m - n; i++) {// 哈希值相等且字符串相等时,返回匹配的起始位置if (p === t && text.substring(i, i + n) === pattern) {return i; // 返回匹配的起始位置}// 更新文本串的哈希值if (i < m - n) {t = (d * (t - text.charCodeAt(i) * h) + text.charCodeAt(i + n)) % q;if (t < 0) {t += q;}}}// 没有找到匹配return -1; // 没有找到匹配
}// 示例用法
const text = "hello world";
const pattern = "world";
console.log(rabinKarp(text, pattern)); // 输出: 6
相关文章:
字符串匹配算法:暴力匹配、KMP 算法、Boyer-Moore 算法、Rabin-Karp 算法
字符串匹配算法 字符串匹配算法是在一个字符串(称为文本)中查找另一个字符串(称为模式)出现的位置或者是否存在的算法。常见的字符串匹配算法包括暴力匹配、KMP算法、Boyer-Moore算法和Rabin-Karp算法。下面是对这些算法的简要介…...
微信小程序接入百度地图(微信小程序插件)使用文档
第一步配置域名 :在微信公众平台登录后配置服务域名称:https://apis.map.qq.com 第二步申请密钥 申请开发者密钥申请地址 第三步使用插件 选择添加插件 搜索腾讯位置服务地图选点 选择要授权的小程序 授权完毕会在这里显示插件信息 第四步查看使用文档 跳转至文…...
如果需要在Log4j中记录特定的异常信息,应该如何实现?如何动态地更改Log4j的日志级别?
如果需要在Log4j中记录特定的异常信息,应该如何实现? 在Log4j中记录特定的异常信息,你可以使用Logger类的error、warn、info等方法,这些方法通常接受一个字符串消息和一个Throwable对象(如异常)作为参数。下…...
Rust入门:C++和Rust动态库(dll)的相互调用
无论是C调用Rust动态库还是Rust调用C动态库,其操作基本都是一样地简单,基本和C调用C的动态库没什么区别,只需要列出所需要导入的函数,并链接到相应的lib文件即可。 这里,在windows中,我们以dll动态库为例说…...
第三篇【传奇开心果系列】Python的自动化办公库技术点案例示例:深度解读Pandas股票市场数据分析
传奇开心果博文系列 系列博文目录Python的自动化办公库技术点案例示例系列 博文目录前言一、Pandas进行股票市场数据分析常见步骤和示例代码1. 加载数据2. 数据清洗和准备3. 分析股票价格和交易量4. 财务数据分析 二、扩展思路介绍1. 技术指标分析2. 波动性分析3. 相关性分析4.…...
3.11笔记2
目前使用的格里高利历闰年的规则如下: 公元年分非4的倍数,为平年。公元年分为4的倍数但非100的倍数,为闰年。公元年分为100的倍数但非400的倍数,为平年。公元年分为400的倍数为闰年。 请用一个表达式 (不能添加括号) 判断某一年…...
web服务器基础
目录 web服务器简介 (1)什么是www (2)网址及HTTP简介 (3)http协议请求的工作流程 主配置文件内的参数 目录标签 缺点 虚拟主机vhosts 示例的格式如下 实例 多IP实现多网页 修改监听端口号 hosts文件及域名解析 修改hosts文件内缓存格式 实现效果 实现多域名解析IP地址 在linux…...
矢量图片转换软件Vector Magic mac中文版功能特色
Vector Magic mac中文版是一款非常流行的矢量图片转换软件,它的功能特色主要体现在以下几个方面: 首先,Vector Magic mac中文版拥有出色的矢量转换能力。它采用世界上最好的全彩色自动描摹器,能够将JPG、PNG、BMP和GIF等位图图像…...
Window部署Oracle并实现公网环境远程访问本地数据库
文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle,是甲骨文公司的一款关系…...
灵魂指针,教给(三)
欢迎来到白刘的领域 Miracle_86.-CSDN博客 系列专栏 C语言知识 先赞后看,已成习惯 创作不易,多多支持! 目录 一、 字符指针变量 二、数组指针变量 2.1 数组指针变量是什么 2.2 数组指针变量如何初始化 三、二维数组传参本质 四、函数…...
纯手工搭建一个springboot maven项目
前言:idea社区版无法自动搭建项目,手动搭建的经验分享如下: 1 包结构 参考下图: 2 项目结构 3 maven依赖 具体的项目包结构如下图: 依据这个项目包结构配置一个springboot 的 pom依赖: <?xml ve…...
【Java】使用`LinkedList`类来实现一个队列,并通过继承`AbstractQueue`或者实现`Queue`接口来实现自定义队列
使用LinkedList类来实现一个队列,并通过继承AbstractQueue或者实现Queue接口来实现自定义队列。 以下是一个简单的示例,其中队列的大小与另一个List的容量保持一致: import java.util.LinkedList; import java.util.List; import java.util…...
ChatGPT消息发不出去了?我找到解决方案了
现象 今天忽然发现 ChatGPT无法发送消息,能查看历史对话,但是无法发送消息。 猜测原因 出现这个问题的各位,应该都是点击登录后顶部弹窗邀请[加入多语言 alapha 测试]了,并且语言选择了中文,抓包看到ab.chatgpt.com…...
《量子计算:下一个大风口,还是一个热炒概念?》
引言 量子计算,作为一项颠覆性的技术,一直以来备受关注。它被认为是未来计算领域的一次革命,可能改变我们对计算能力和数据处理的理解。然而,随着技术的不断进步和商业应用的探索,人们开始思考,量子计算到底是一个即将到来的大风口,还是一个被过度炒作的概念? 量子计…...
在Ubuntu中如何基于conda安装jupyterlab
在Ubuntu中如何创建ipykernel 可以用下面命令完成 conda create -n newenv python3.8conda activate enwenvconda install ipykernel5.1.4conda install ipython_genutilsipython -m ipykernel install --user --namepython3 --display-name Python3conda install -c conda-fo…...
Unity 中的 PlayFab 入门
要开始在 Unity 中使用 PlayFab,你只需执行以下两个简单步骤即可。第一步是设置 PlayFab 帐户。第二步是通过安装 Unity 编辑器扩展将其连接到 Unity。或者,你也可以下载 PlayFab SDK 并在没有扩展的情况下进行配置。 设置你的 PlayFab 帐户 访问 PlayFab 的网站并创建你的…...
常见排序算法(C++)
评判一个排序算法时除了时间复杂度和空间复杂度之外还要考虑对cache的捕获效果如何,cache友好的排序算法应该对数据的访问相对集中,快速排序相较于堆排序优点就是在于对cache的捕获效果好。 堆排序 时间复杂度:O(n log n …...
多线程编程互斥锁mutex的创建
在Linux下的多线程编程中,互斥锁(mutex)的创建主要有两种方式:静态分配和动态分配。这两种方式的主要区别在于互斥锁的生命周期和初始化方式。 静态分配(静态方式) 静态分配方式是在程序编译时就已经确定互…...
在 SpringBoot3 中使用 Mybatis-Plus 报错
在 SpringBoot3 中使用 Mybatis-Plus 报错 Property ‘sqlSessionFactory’ or ‘sqlSessionTemplate’ are required Caused by: java.lang.IllegalArgumentException: Property sqlSessionFactory or sqlSessionTemplate are requiredat org.springframework.util.Assert.no…...
【libwebrtc】基于m114的构建
libwebrtc A C++ wrapper for binary release, mainly used for flutter-webrtc desktop (windows, linux, embedded).是 基于m114版本的webrtc 最新(20240309 ) 的是m122了。官方给出的构建过程 .gclient 文件 solutions = [{"name" : src,"url...
筑牢代码安全基石:GB/T 34943/34944 标准详解与库博静态分析工具的全面支持
一、标准概述:GB/T 34943 与 GB/T 34944 国家标准在软件安全日益成为国家信息化战略核心的背景下,GB/T 34943-2017《C/C 语言源代码漏洞测试规范》与 GB/T 34944-2017《Java 语言源代码漏洞测试规范》两项国家标准应运而生国家标准化管理委员会。由全国信…...
ICLR 2026两篇满分思路:不规则时间序列+条件扩散模型,研一就能复现!
时序生成式预测在金融与医疗等高风险领域至关重要。面对数据非平稳性、极端事件冲击及采样不规则等严峻挑战,传统点预测常因过度自信而失效,产生巨大风险。本文解析的两项最新研究开辟了新路径:前者首创不确定性门控(Uncertainty-…...
硬件笔记——使用OrCAD绘制原理图
一、新建工程新建工程,并输入工程的名称和路径,然后会弹出一个PAGE页面:二、修改PAGE页面大小有几种尺寸规格,也可以自定义尺寸,这里以尺寸B规格为例:三、添加原理图库到工程里点击工具栏右上角的芯片图标&…...
嵌入式NTP客户端:一次校准,离线维持49天高精度时间
1. 项目概述PREi NTP Manager 是一个专为嵌入式平台(尤其是 ESP 系列微控制器)设计的轻量级网络时间协议(NTP)客户端库。其核心目标并非实现完整的 RFC 5905 NTP 协议栈,而是以极简、可靠、低资源占用的方式࿰…...
深度学习_YOLO,卡尔曼滤波和
1.YOLO 1.1 简介 YOLO系列算法是一类典型的one-stage目标检测算法,其利用anchor box将分类与目标定位的回归问题结合起来,从而做到了高效、灵活和泛化性能好,所以在工业界也十分受欢迎. Yolo算法采用一个单独的CNN模型实现end-to-end的目标检…...
YOLO 系列专栏(三十七)【全网首发】YOLO26 独家卷积改进|CVPR 2025 FDConv 频率动态卷积,结合 FDC3k2 二次创新,突破小目标特征表达瓶颈
目录 摘要 一、引言:传统卷积的小目标痛点 二、核心技术原理解析 2.1 FDConv 频率动态卷积(CVPR 2025 核心思想) 2.1.1 核心流程 2.1.2 关键优势 2.2 FDC3k2 二次创新模块(全网首发) 2.2.1 结构设计 2.3 FDConv vs 传统卷积/主流动态卷积(小目标场景对比) 三、…...
STM32 UART 通信详解
通用异步收发传输器(UART)是STM32微控制器中最基础、最常用的串行通信接口之一。它通过简单的两根信号线(TX和RX)实现全双工异步数据交换,广泛应用于与PC调试、传感器模块、蓝牙/Wi-Fi模块等的通信。一、UART协议基础1…...
构建仓库与包管理
一、构建仓库 1、nexus安装 brew安装方式(比较慢) brew install nexus官网下载安装方式 去sonatype官网下载,比如MacOS的,下载完成之后cd到bin目录即可看到启动命令 启动 # 2.0版本 brew services start nexus # 3.0版本 /usr…...
Qwen3.5-9B实战教程:WebSocket流式响应+前端实时渲染优化方案
Qwen3.5-9B实战教程:WebSocket流式响应前端实时渲染优化方案 1. 项目概述与核心能力 Qwen3.5-9B是一款拥有90亿参数的开源大语言模型,在多个领域展现出强大的能力: 强逻辑推理:能够处理复杂的逻辑问题,适合需要深度…...
.NET 9容器化调试黄金三角(dotnet-monitor + OpenTelemetry + VS Code Dev Containers),2024 Q3微软内部培训绝密资料首次公开
第一章:.NET 9容器化调试黄金三角全景图.NET 9 容器化调试的“黄金三角”由 **源码映射(Source Link)**、**容器内调试代理(vsdbg in container)** 和 **Docker Compose 集成调试配置** 三者构成,三者协同实…...
