字符串匹配算法--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
| A | B | E | R | 其他 |
|---|---|---|---|---|
| 4 | 2 | 1 | 3 | 6 |
其代表的是
如果该字符串当前不匹配,那么字符串向右移动的距离。
代码
这里是用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算法
该算法解决的是字符串匹配问题,即查看字符串中是否含有完整的匹配字符串。如在java的string的contains方法匹配问题最简单的就是暴力破解了。在java的contains也是这么实现的,效率是低一点的。如果想要更快的速度可以自己写KMP算法。 代码实现体验 Knut…...
swagger的简单介绍
目录 swagger是什么? swagger有什么用? Swagger包含的工具集: swagger的使用步骤: swagger的相关注解: Docket的源码 了解swagger的作用和概念了解前后端分离在SpringBoot中集成Swagger swagger是什么?…...
HNU-电路与电子学-小班3
第三次讨论 1 、直接用晶体管而不是逻辑门实现异或门,并解释这个电路是如何工作的。 (6个 MOS 管构成) 2 、通信双方约定采用 7 位海明码进行数据传输。请为发送方设计海明码校验位 生成电路,采用功能块和逻辑门为接收方设计海…...
[机缘参悟-98] :层次不同、维度不同、视角不同、结论不同
目录 全局VS具备, 总体V部分 认知的六个认知层次: 认知的六个立体化维度: 0、维空间,点思维 1、一维空间,直线思维 2、二维空间,平面思维 3、三维空间:立体思维。 4、四维空间ÿ…...
chatgpt-web发布之docker打包流程
docker打包流程 1、使用docker前置准备: 电脑下载docker桌面版,以及开启虚拟机步骤:https://blog.csdn.net/qq_34905631/article/details/126573826下载docker桌面版 :https://docs.docker.com/desktop/install/windows-install…...
动态优化会议地点
前言 在现在快节奏的工作节奏下,大家的活动范围越来越广,但是出行成本也相应提高。在集体会面的时候,如何选择合适的地点成为了一个棘手的问题。本文将介绍如何通过动态优化选择会议地点,以达到平均交通成本最低的目标。 动态优化…...
Golang每日一练(leetDay0076) 第k大元素、组合总和III
目录 215. 数组中的第K个最大元素 Kth-largest-element-in-an-array 🌟🌟 216. 组合总和 III Combination Sum iii 🌟🌟 🌟 每日一练刷题专栏 🌟 Rust每日一练 专栏 Golang每日一练 专栏 Python每日…...
可节省60% MCU开发成本的NV080D-S8,单片机语音芯片在恒温碗上的应用
社会在不断进步,科技在不断发展,如今的恒温碗不仅带有温度显示功能,更附带有语音播报,能更好地知晓当前饭菜,变凉或过烫的情况,有效避免伤害宝宝脆弱的肠胃; 广州九芯电子推出了一款,…...
Java并发常见面试题
参考:javauide、程序员大斌、面试宝典 1.并发与并行的区别 并发:两个及两个以上的作业在同一 时间段 内执行。并行:两个及两个以上的作业在同一 时刻 执行。2.同步和异步的区别 同步:发出一个调用之后,在没有得到结果之前, 该调用就不可以返回,一直等待。异步:调用在发…...
基于vue3+pinia2仿ChatGPT聊天实例|vite4.x仿chatgpt界面
使用vue3pinia2开发仿制chatgpt界面聊天实例Vue3-Chatgpt 基于Vue3.xPinia2VueRouterVue3-Markdown等技术构建仿ChatGPT网页端聊天程序。支持经典分栏界面布局、light/dark模式、全屏半屏显示、Markdown语法解析、侧边栏隐藏等功能。 技术框架 编辑工具:Cursor框架…...
JDK动态代理和CGLIB动态代理
JDK动态代理和CGLIB动态代理 JDK动态代理和CGLIB动态代理 JDK动态代理和CGLIB动态代理 ① JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时&#x…...
Jetpack Hilt 框架的基本使用
什么是 Hilt? Hilt 是一个功能强大、用法简单的依赖注入框架,于 2020 年加入到 Jetpack 家族中。它是 Android 团队联系了 Dagger2 团队,一起开发出来的一个专门面向 Android 的依赖注入框架。相比于 Dagger2,Hilt 最明显的特征就…...
exec()在不同namespace执行结果的区别
记录一个很tricky的问题,下面这段code在执行func1时会出现NameError: name List is not defined,但执行func2时一切正常。 import typescontent """ from typing import Listclass GeneratedData:qna: List"""def func1…...
人工智能革命中的22个隐藏职业:推动科技行业的变革
作者 | Manas Sadangi 随着人工智能技术的不断发展,它正在创造一系列前所未有的就业机会。虽然数据科学家、机器学习工程师和人工智能研究人员等传统的人工智能角色得到了广泛认可,但在推动科技行业变革方面,还有一些鲜为人知的职业同样重要。…...
算法题3 — 求字符串中的最长子串
文章目录 题目示例示例1示例2示例3 解题解法1解法2 leetcode 题目 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例1 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例…...
【FreeRTOS】——中断优先级设置中断相关寄存器临界段代码保护调度器挂起与恢复
目录 前言: 一、中断优先级设置 二、中断相关寄存器(STM32-Cortex M3) 三、临界段代码保护 四、任务调度器的挂起和恢复 总结: 前言: 博客笔记根据正点原子视频教程编辑,仅供学习交流使用࿰…...
1.2 什么是eBPF?(下)
四,eBPF的优势 4.1 eBPF程序的动态加载 eBPF程序可以动态地加载到内核中,或从内核中删除。这个要与内核模块的加载与卸载区分开来。这里顺便讨论下eBPF程序与内核模块的区别,如下: 而Linux内核模块是面向内核API编程的,可以直接运行在内核当中。eBPF程序是面向BPF体系结构…...
掌握哪些测试技术才能说自己已经学成了?
一、过硬的基础能力 其实所有的测试大佬都是从底层基础开始的,随着时间,经验的积累慢慢变成大佬。要想稳扎稳打在测试行业深耕,成为测试大牛,首当其冲的肯定就是拥有过硬的基础,所有的基础都是根基,后期所…...
什么是C语言?
C语言是一种高级编程语言,于1972年由Dennis Ritchie在贝尔实验室开发出来。它是一种通用的、结构化的编程语言,被广泛用于系统软件、嵌入式系统、游戏开发以及科学计算等领域。 C语言的设计目标是提供一种简洁、高效、可移植的编程语言,以便…...
SAP-物料主数据-质量管理视图字段解析
过账到质检库存:要勾选,否则收货后库存不进入质检库存HU检验:收货到启用HU管理的库位时产生检验批,例如某个成品物料是收货到C002库位,该库位启用了HU管理,那么此处要勾选。但是如果勾选了,却收…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...
