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

字符串匹配算法--KMP算法--BM算法

该算法解决的是字符串匹配问题,即查看字符串中是否含有完整的匹配字符串。如在java的string的contains方法

匹配问题最简单的就是暴力破解了。在java的contains也是这么实现的,效率是低一点的。如果想要更快的速度可以自己写KMP算法。

代码实现体验

Knuth-Morris-Pratt

KMP算法也不是特别高级的一种,只是对暴力法的一种优化,节省了很多不必要的匹配过程。

假定:
文本为A子串
匹配文本为B子串

在这里插入图片描述
这里是相同的
在这里插入图片描述
如果假定2号是匹配上的那么画线部分应该需要匹配上
在这里插入图片描述
3号同理

这里可以看出来
如果匹配成功A后缀对应的会是匹配成功B前缀。
所以我们如果发现A后缀和B前缀相同就可以将B移动到那个位置。
我们会发现A后缀和B前缀都会是B的一部分(因为匹配成功了)
所以移动的位置只和B有关,我们就可以构建一个前缀表。如果匹配了 i i i 个字符那么就移动 n e x t [ i ] next[i] next[i] 位。

所以如何获取next表呢
用双指针
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
为什么呢:
这里利用的应该算动态规划的思想。
我们首先看next代表的是什么:

next代表对于前面部分匹配成功而最后一个匹配识别而指针指向的方向

那么我们可以知道上面的这个情况就等同于文本为AAAB匹配文为AAA的情况了。那么这个时候我们就需要将匹配文指针指向next[]

	protected static int[] getNext(String pattern) {// 初始化next数组和指针int[] next = new int[pattern.length()];next[0] = -1;// 后缀指针int i = 0;// 前缀指针int j = -1;// 生成next数组while (i < pattern.length() - 1) {// j == -1 代表j已经到了开头if (j == -1 || pattern.charAt(i) == pattern.charAt(j)) {i++;j++;next[i] = j;} else {j = next[j];}}return next;}

因为这个生成匹配next数组和这个的思想是一样的。这里直接给出代码了

  private static int KMPMatch(String text,String pattern,int[] next){int i = 0;int j = 0;while (i < text.length() && j < pattern.length()) {if (j == -1 || text.charAt(i) == pattern.charAt(j)) {i++;j++;} else {j = next[j];}}if (j == pattern.length())return i - j;elsereturn -1;}

在这里插入图片描述

Boyer-Moore

KMP算法是从左到右比较,而BM算法从右到左比较。而BM的这种做法也使得算法变得更简单了。

简化版本Horspool算法

就是从最后一个开始匹配如果没有匹配成功,则将离末尾最近的一个拿过来匹配。

在这里插入图片描述
那么就将最近的A移动过来,然后继续从最后一位开始匹配
在这里插入图片描述

这样可以大大的减少匹配的次数。
为了加快移动的速度,我们可以用一个匹配表来加速。

如BARBER

ABER其他
42136

其代表的是
如果该字符串当前不匹配,那么字符串向右移动的距离。
代码
这里是用map实现的,也可以用数组实现。在最开始的运行代码里面有。

private static Map<Character, Integer> getTable(String pattern) {HashMap<Character, Integer> table = new HashMap<>();for (int i = 0; i < pattern.length() - 1; i++)table.put(pattern.charAt(i), pattern.length() - 1 - i);return table;}public static int horspool(String text, String pattern) {Map<Character, Integer> table = getTable(pattern);int offset = 0;while (offset <= text.length() - pattern.length()) {int i = pattern.length() - 1;while (i >= 0 && pattern.charAt(i) == text.charAt(offset + i)) i--;if (i < 0)return offset;else offset += table.getOrDefault(text.charAt(offset + pattern.length() - 1), pattern.length());}return -1;}

在这里插入图片描述

Boyer-Moore算法

BM算法是是在horspool算法的进一步优化。
然而在遇到第一个不匹配字符之前已经有k个字符匹配成功了,那么这2个算法的操作是不同的。

BM算法定义了两个规则:

  • 坏字符规则:当文本串中的某个字符跟模式串的某个字符不匹配时,我们称文本串中的这个失配字符为坏字符,此时:
    移动位数 d 1 = m a x { t 1 ( 失配字符 ) − 已经匹配字符数量 , 1 } 移动位数d_1=max\{t_1(失配字符)-已经匹配字符数量,1\} 移动位数d1=max{t1(失配字符)已经匹配字符数量,1}
    t 1 的表和 h o r s p o l l 的是一样的 t_1的表和horspoll的是一样的 t1的表和horspoll的是一样的
  • 好后缀规则:当字符失配时,已经匹配上的我们称为好后缀。
    移动位数 d 2 = 后缀移动表 t 2 ( 匹配字符数量 ) 移动位数d_2=后缀移动表t_2(匹配字符数量) 移动位数d2=后缀移动表t2(匹配字符数量)
  • 总的移动 = m a x { d 1 , d 2 } = max\{d_1,d_2\} =max{d1,d2}

坏字符我们已经学过了。
我们来看看好后缀是如何建表的。
好后缀就是相当于,在匹配文本中寻找本次已经匹配的后缀是否含有。
如下:
在这里插入图片描述

这个原理应该很好理解但是,代码怎么来实现呢。
getTable(pattern);就是上面的代码。

public static int match(String text, String pattern) {buildSuffixTable(pattern);getTable(pattern);int offset = 0;int l = pattern.length();while (offset <= text.length() - l) {int i = l - 1;while (i >= 0 && pattern.charAt(i) == text.charAt(offset + i)) {i--;}if (i < 0) {
//                System.out.println(offset + 1);
//                offset++;return offset;} else if (i == l - 1) {offset += table.getOrDefault(text.charAt(offset + i), l);} else {int d1 = Math.max(1, table.getOrDefault(text.charAt(offset + l - 1), l) - i);offset += Math.max(d1, gs[l - 1 - i]);}}return -1;}private static int[] gs;protected static void buildSuffixTable(String s) {char[] pattern = s.toCharArray();gs = new int[pattern.length]; // 模式串int[] suffix = new int[pattern.length];Arrays.fill(suffix, -1);for (int i = 1; i <= pattern.length - 1; i++) {int j = i - 1;int k = 0;while (j >= 0 && pattern[j] == pattern[pattern.length - 1 - k]) {j--;k++;suffix[k] = j + 1;}}
//        System.out.println(Arrays.toString(suffix));int i = 1;while (i < suffix.length && suffix[i] != -1) {gs[i] = pattern.length - i - suffix[i];i++;}int j = i - 1;while (j >= 0) {if (s.substring(s.length() - j).equals(s.substring(0, j))) {Arrays.fill(gs, i, gs.length, gs.length - j);break;}j--;}if (j == -1)Arrays.fill(gs, i, gs.length, gs.length);}

但是效果来说呢没有快哎。
在这里插入图片描述

相关文章:

字符串匹配算法--KMP算法--BM算法

该算法解决的是字符串匹配问题&#xff0c;即查看字符串中是否含有完整的匹配字符串。如在java的string的contains方法匹配问题最简单的就是暴力破解了。在java的contains也是这么实现的&#xff0c;效率是低一点的。如果想要更快的速度可以自己写KMP算法。 代码实现体验 Knut…...

swagger的简单介绍

目录 swagger是什么&#xff1f; swagger有什么用&#xff1f; Swagger包含的工具集&#xff1a; swagger的使用步骤&#xff1a; swagger的相关注解&#xff1a; Docket的源码 了解swagger的作用和概念了解前后端分离在SpringBoot中集成Swagger swagger是什么&#xff1f;…...

HNU-电路与电子学-小班3

第三次讨论 1 、直接用晶体管而不是逻辑门实现异或门&#xff0c;并解释这个电路是如何工作的。 &#xff08;6个 MOS 管构成&#xff09; 2 、通信双方约定采用 7 位海明码进行数据传输。请为发送方设计海明码校验位 生成电路&#xff0c;采用功能块和逻辑门为接收方设计海…...

[机缘参悟-98] :层次不同、维度不同、视角不同、结论不同

目录 全局VS具备&#xff0c; 总体V部分 认知的六个认知层次&#xff1a; 认知的六个立体化维度&#xff1a; 0、维空间&#xff0c;点思维 1、一维空间&#xff0c;直线思维 2、二维空间&#xff0c;平面思维 3、三维空间&#xff1a;立体思维。 4、四维空间&#xff…...

chatgpt-web发布之docker打包流程

docker打包流程 1、使用docker前置准备&#xff1a; 电脑下载docker桌面版&#xff0c;以及开启虚拟机步骤&#xff1a;https://blog.csdn.net/qq_34905631/article/details/126573826下载docker桌面版 &#xff1a;https://docs.docker.com/desktop/install/windows-install…...

动态优化会议地点

前言 在现在快节奏的工作节奏下&#xff0c;大家的活动范围越来越广&#xff0c;但是出行成本也相应提高。在集体会面的时候&#xff0c;如何选择合适的地点成为了一个棘手的问题。本文将介绍如何通过动态优化选择会议地点&#xff0c;以达到平均交通成本最低的目标。 动态优化…...

Golang每日一练(leetDay0076) 第k大元素、组合总和III

目录 215. 数组中的第K个最大元素 Kth-largest-element-in-an-array &#x1f31f;&#x1f31f; 216. 组合总和 III Combination Sum iii &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日…...

可节省60% MCU开发成本的NV080D-S8,单片机语音芯片在恒温碗上的应用

社会在不断进步&#xff0c;科技在不断发展&#xff0c;如今的恒温碗不仅带有温度显示功能&#xff0c;更附带有语音播报&#xff0c;能更好地知晓当前饭菜&#xff0c;变凉或过烫的情况&#xff0c;有效避免伤害宝宝脆弱的肠胃&#xff1b; 广州九芯电子推出了一款&#xff0c…...

Java并发常见面试题

参考:javauide、程序员大斌、面试宝典 1.并发与并行的区别 并发:两个及两个以上的作业在同一 时间段 内执行。并行:两个及两个以上的作业在同一 时刻 执行。2.同步和异步的区别 同步:发出一个调用之后,在没有得到结果之前, 该调用就不可以返回,一直等待。异步:调用在发…...

基于vue3+pinia2仿ChatGPT聊天实例|vite4.x仿chatgpt界面

使用vue3pinia2开发仿制chatgpt界面聊天实例Vue3-Chatgpt 基于Vue3.xPinia2VueRouterVue3-Markdown等技术构建仿ChatGPT网页端聊天程序。支持经典分栏界面布局、light/dark模式、全屏半屏显示、Markdown语法解析、侧边栏隐藏等功能。 技术框架 编辑工具&#xff1a;Cursor框架…...

JDK动态代理和CGLIB动态代理

JDK动态代理和CGLIB动态代理 JDK动态代理和CGLIB动态代理 JDK动态代理和CGLIB动态代理 ① JDK动态代理只提供接口的代理&#xff0c;不支持类的代理&#xff0c;要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类&#xff0c;在获取代理对象时&#x…...

Jetpack Hilt 框架的基本使用

什么是 Hilt&#xff1f; Hilt 是一个功能强大、用法简单的依赖注入框架&#xff0c;于 2020 年加入到 Jetpack 家族中。它是 Android 团队联系了 Dagger2 团队&#xff0c;一起开发出来的一个专门面向 Android 的依赖注入框架。相比于 Dagger2&#xff0c;Hilt 最明显的特征就…...

exec()在不同namespace执行结果的区别

记录一个很tricky的问题&#xff0c;下面这段code在执行func1时会出现NameError: name List is not defined&#xff0c;但执行func2时一切正常。 import typescontent """ from typing import Listclass GeneratedData:qna: List"""def func1…...

人工智能革命中的22个隐藏职业:推动科技行业的变革

作者 | Manas Sadangi 随着人工智能技术的不断发展&#xff0c;它正在创造一系列前所未有的就业机会。虽然数据科学家、机器学习工程师和人工智能研究人员等传统的人工智能角色得到了广泛认可&#xff0c;但在推动科技行业变革方面&#xff0c;还有一些鲜为人知的职业同样重要。…...

算法题3 — 求字符串中的最长子串

文章目录 题目示例示例1示例2示例3 解题解法1解法2 leetcode 题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例1 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例…...

【FreeRTOS】——中断优先级设置中断相关寄存器临界段代码保护调度器挂起与恢复

目录 前言&#xff1a; 一、中断优先级设置 二、中断相关寄存器&#xff08;STM32-Cortex M3&#xff09; 三、临界段代码保护 四、任务调度器的挂起和恢复 总结&#xff1a; 前言&#xff1a; 博客笔记根据正点原子视频教程编辑&#xff0c;仅供学习交流使用&#xff0…...

1.2 什么是eBPF?(下)

四,eBPF的优势 4.1 eBPF程序的动态加载 eBPF程序可以动态地加载到内核中,或从内核中删除。这个要与内核模块的加载与卸载区分开来。这里顺便讨论下eBPF程序与内核模块的区别,如下: 而Linux内核模块是面向内核API编程的,可以直接运行在内核当中。eBPF程序是面向BPF体系结构…...

掌握哪些测试技术才能说自己已经学成了?

一、过硬的基础能力 其实所有的测试大佬都是从底层基础开始的&#xff0c;随着时间&#xff0c;经验的积累慢慢变成大佬。要想稳扎稳打在测试行业深耕&#xff0c;成为测试大牛&#xff0c;首当其冲的肯定就是拥有过硬的基础&#xff0c;所有的基础都是根基&#xff0c;后期所…...

什么是C语言?

C语言是一种高级编程语言&#xff0c;于1972年由Dennis Ritchie在贝尔实验室开发出来。它是一种通用的、结构化的编程语言&#xff0c;被广泛用于系统软件、嵌入式系统、游戏开发以及科学计算等领域。 C语言的设计目标是提供一种简洁、高效、可移植的编程语言&#xff0c;以便…...

SAP-物料主数据-质量管理视图字段解析

过账到质检库存&#xff1a;要勾选&#xff0c;否则收货后库存不进入质检库存HU检验&#xff1a;收货到启用HU管理的库位时产生检验批&#xff0c;例如某个成品物料是收货到C002库位&#xff0c;该库位启用了HU管理&#xff0c;那么此处要勾选。但是如果勾选了&#xff0c;却收…...

谷氨酸发酵过程的软测量建模【附模型】

✨ 长期致力于软测量、谷氨酸发酵、动力学模型、支持向量机、高斯过程、变量选择、异常状态研究工作&#xff0c;擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流&#xff0c;点击《获取方式》 &#xff08;1&#xff09;多阶段高斯…...

3分钟快速安装BetterNCM插件管理器,让你的网易云音乐功能翻倍

3分钟快速安装BetterNCM插件管理器&#xff0c;让你的网易云音乐功能翻倍 【免费下载链接】BetterNCM-Installer 一键安装 Better 系软件 项目地址: https://gitcode.com/gh_mirrors/be/BetterNCM-Installer 还在为网易云音乐功能单一而烦恼吗&#xff1f;想要解锁更多个…...

OpenCore Legacy Patcher完全指南:3步让旧款Mac焕发新生的终极方案

OpenCore Legacy Patcher完全指南&#xff1a;3步让旧款Mac焕发新生的终极方案 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你是否拥有一台性能尚可但已被…...

php有什么版本,php语言有几个版本

php有什么版本,php语言有几个版本PHP的大版本主要分四支&#xff1a;PHP4/PHP5/PHP6/PHP7 其中&#xff0c;PHP4由于太古老、对OO支持不力已基本被淘汰&#xff0c;请无视PHP4。 PHP6由于基本没有生产线上的应用&#xff0c;还基本只是一款概念产品&#xff0c;很多功能已在PHP…...

5步彻底解决Windows DLL加载冲突:UE4SS系统故障排查指南

5步彻底解决Windows DLL加载冲突&#xff1a;UE4SS系统故障排查指南 【免费下载链接】RE-UE4SS Injectable LUA scripting system, SDK generator, live property editor and other dumping utilities for UE4/5 games 项目地址: https://gitcode.com/gh_mirrors/re/RE-UE4SS…...

收藏|2026年大模型算法岗崛起!程序员小白入门高薪赛道全攻略

前些年&#xff0c;算法岗位一直稳居技术圈高薪行列&#xff0c;无数程序员争相入局&#xff0c;也成为计算机专业毕业生求职首选方向。 伴随大模型技术飞速迭代落地&#xff0c;行业就业格局迎来重大变革。如今含金量最高、人才缺口最大、长期发展潜力顶尖的岗位&#xff0c;已…...

基于STM32WL与LoRaWAN的远程空气质量监测系统全栈开发实践

1. 项目概述&#xff1a;构建一个远程空气质量监测系统最近在做一个挺有意思的玩意儿&#xff1a;一个能自己找地方待着、靠太阳能供电&#xff0c;然后把周围空气数据悄无声息传回来的远程监测终端。核心想法很简单&#xff0c;就是想知道某个犄角旮旯&#xff0c;比如工厂周边…...

纯硬件实现I2C协议:从逻辑门到传感器通信的深度实践

1. 项目概述&#xff1a;用纯硬件“解剖”I2C总线很多朋友在玩传感器&#xff0c;尤其是温湿度传感器时&#xff0c;都绕不开I2C这个通信协议。市面上绝大多数的教程和方案&#xff0c;都会告诉你&#xff1a;找个单片机&#xff08;比如Arduino、STM32&#xff09;&#xff0c…...

从Stable Diffusion到DiT:为什么说Transformer是扩散模型的下一站?

从Stable Diffusion到DiT&#xff1a;Transformer如何重塑扩散模型的未来 在图像生成领域&#xff0c;扩散模型正经历着从U-Net架构向Transformer架构的范式转移。这一转变不仅仅是技术组件的简单替换&#xff0c;而是代表着生成式AI在可扩展性、训练效率和模型容量方面的重大突…...

PagerLayoutManager:让Android网格分页布局实现变得简单高效的终极方案

PagerLayoutManager&#xff1a;让Android网格分页布局实现变得简单高效的终极方案 【免费下载链接】pager-layoutmanager [暂停维护]Android 网格分页布局。 项目地址: https://gitcode.com/gh_mirrors/pa/pager-layoutmanager PagerLayoutManager是一款专为Android开发…...