字符串匹配算法:暴力匹配、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

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

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

相关文章

【数据结构】初识二叉搜索树(Binary Search Tree)

文章目录 1. 二叉搜索树的概念2. 二叉搜索树的操作1.1 二叉搜索树的查找1.2 二叉搜索树的插入1.3 二叉搜索树的删除 1. 二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它可能是一棵空树&#xff0c;也可能是具有以下性质的二叉树&#xff1a; 若它的左子树不为空&am…

力扣L5----- 58. 最后一个单词的长度(2024年3月11日)

1.题目 2.知识点 注1&#xff1a; lastIndexOf()它用于查找指定字符或子字符串在当前字符串中最后一次出现的位置。它的作用是从字符串的末尾向前搜索指定字符或子字符串&#xff0c;并返回其最后一次出现的位置的索引。 &#xff08;1&#xff09;例如&#xff0c;在字符串 …

Rust入门:C++和Rust动态库(dll)的相互调用

无论是C调用Rust动态库还是Rust调用C动态库&#xff0c;其操作基本都是一样地简单&#xff0c;基本和C调用C的动态库没什么区别&#xff0c;只需要列出所需要导入的函数&#xff0c;并链接到相应的lib文件即可。 这里&#xff0c;在windows中&#xff0c;我们以dll动态库为例说…

文件存储组件

File System: 文件系统,例如数据存储的文件、操作日志类(redolog undolog binlog errorlog querylog slowlog data index)、索引文件等存储。 日志文件 常见的日志文件有错误日志、二进制日志、慢查询日志、全查询日志、redo日志、undo日志。 错误日志 对mysql的启动、运行…

OpenCV学习笔记(一)——Anaconda下载和OpenCV的下载

OpenCV是图象识别中有巨大的应用场景&#xff0c;本篇文章以Python为基础。当初学OpenCV的时候&#xff0c;推使用在Anaconda编写代码&#xff0c;原因比较方便&#xff0c;下面我们对于Anaconda的下载过程进行演示。 Anaconda的下载 首先打开官网www.anaconda.com/download找…

数据结构---C语言栈队列

知识点&#xff1a; 栈&#xff1a; 只允许在一端进行插入或删除操作的线性表&#xff0c;先进后出LIFO 类似一摞书&#xff0c;按顺序拿&#xff0c;先放的书只能最后拿&#xff1b; 顺序栈&#xff1a;栈的顺序存储 typedef struct{Elemtype data[50];int top; }SqStack; SqS…

设计模式-行为型模式-模版方法模式

模板方法模式&#xff0c;定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。[DP] 模板方法模式是通过把不变行为搬移到超类&#xff0c;去除子类中的重复代码来体现它的优势。 //首…

【Leetcode每日一题】 位运算 - 面试题 01.01. 判定字符是否唯一(难度⭐)(33)

1.题目解析 题目链接&#xff1a;面试题 01.01. 判定字符是否唯一 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 核心在于判断题目所给字符串是否存在相同字母&#xff0c;存在返回false即可&#xff0c;不存在返回true即可。 …

Caffeine缓存

本地缓存基于本地环境的内存&#xff0c;访问速度非常快&#xff0c;对于一些变更频率低、实时性要求低的数据&#xff0c;可以放在本地缓存中&#xff0c;提升访问速度 使用本地缓存能够减少和Redis类的远程缓存间的数据交互&#xff0c;减少网络 I/O 开销&#xff0c;降低这…

08 聚合函数

聚合函数 我们上一章讲到了 SQL 单行函数。实际上 SQL 函数还有一类&#xff0c;叫做聚合&#xff08;或聚集、分组&#xff09;函数&#xff0c;它是对一组数据进行汇总的函数&#xff0c;输入的是一组数据的集合&#xff0c;输出的是单个值。 1.聚合函数介绍 什么是聚合函…

2、函数、对象、对象方法函数的使用、扩展运算符、箭头函数、symbol

一、函数 1、数字类型的用法 带Number的先判断是不是数字类型 Number.isNaN() 判断是否 是非数值 非数值返回 true数值类型返回 false console.log(Number.isNaN(NaN)); // true console.log(Number.isNaN(false)); // false console.log(Number.isNaN(null)); // false c…

for、while、do...while循环的使用

本篇文章只记录for、while、do...while循环的使用&#xff0c;由于java循环较为简单&#xff0c;所以直接上代码。 1、for循环 需求&#xff1a;循环遍历求和 1-100。 public class Demo {public static void main(String[] args) {int sum 0;for (int i 1; i < 100; i…

Android手机定位

目录 一、定位功能准备 1.申请权限 2.开启定位所需功能 &#xff08;1&#xff09;定位 &#xff08;2&#xff09;WiFi &#xff08;3&#xff09;移动数据连接&#xff08;基站&#xff09; 二、获取定位信息 1.定位条件器 Criteria 2.定位管理器 LocationManager …

YOLOv5目标检测学习(4):YOLOV5源码的文件结构解析

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言①py、cpp、java后缀的文件②md、txt、yml后缀的文件③yaml后缀的文件 一、.github文件夹1.1 workflows文件夹&#xff1a;该文件夹通常包含GitHub Actions 的工…

Python基础语法:基本数据类型(列表)

现实世界中总是存在一组一组的事物。"组"的概念作为基本数据类型的一种&#xff0c;它也是来源于我们去解决现实生活中的一些问题而产生的。它需要有“组”这样的一个数据类型来丰富我们的基本数据类型。 那么在Python中如何来表示“组”的概念呢&#xff1f; 在Py…

RHEL9 DNF/YUM仓库管理软件包

DNF/YUM仓库管理软件包 一个基于RPM包的软件包管理器能够从指定的服务器自动下载RPM包并且安装&#xff0c;自动处理依赖性关系&#xff0c;并且一次性安装所有依赖的软件包C/S模式 Server服务端提供RPM软件包与数据库文件repodataClient客户端使用dnf仓库 常用组合 组合参…

解决Klipper下位机ID获取失败问题

使用硬件&#xff1a; 上位机&#xff1a;必趣派&#xff0c;版本CB1_Debian11_Klipper_kernel5.16_20230303 下位机&#xff1a;八爪鱼STM32F407 问题&#xff1a;上位机获取下位机ID失败。 解决&#xff1a;咨询DIY群友&#xff0c;也对这个问题不太了解。我调试过程中&…

Python 导入Excel三维坐标数据 生成三维曲面地形图(面) 4-1、线条平滑曲面(原始图形)

环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata fro…

SPI学习笔记

总线介绍 SPI&#xff0c;是英语Serial Peripheral interface的缩写&#xff0c;顾名思义就是串行外设接口。SPI协议主要作为主控芯片去配置外围芯片的接口协议。SPI接口主要应用在 EEPROM&#xff0c;FLASH&#xff0c;实时时钟&#xff0c;AD转换器&#xff0c;还有数字信号…

【vivado】 clock wizard 时钟IP

一、前言 MMCM和PLL是在FPGA设计中不可避免需要使用到的时钟资源&#xff0c;对于其功能及使用方法的理解是正确进行FPGA设计的前提。 二、Xilinx 时钟 IP配置 vivado中使用时钟向导(Clocking Wizard)配置时钟IP核&#xff0c;其框图如下&#xff1a; clk_in 输入时钟&#…