Java-KMP字符串匹配算法
给两个字符串s和t,如何很快的知道s是否包含t(即t是否是s的子串)。暴力的方法,我们依次以s每个位置为头,去匹配t。
public int find(String s, String t) {char[] ss = s.toCharArray();char[] tt = t.toCharArray();int i = 0;while (i < ss.length) {int j = 0;//以s的每个位置为头匹配int start = i;while (start < ss.length&& j < tt.length) {//有一个不等直接break,匹配下一个位置开头的串if (ss[start] != tt[j]) {break;}start++;j++;}//如果j来到了t字符串的长度,说明上面的循环第一次匹配上了,返回第一次匹配上的位置下标if (j == tt.length) {return start-tt.length;}//否则,从下一个位置开始匹配i++;}return -1;
}
举例,s=ababeababde,t=ababd。我们看一下暴力解法的过程。
1、i=0,start=0,j=0去循环匹配。start=4,j=4时,不匹配,break。start回退到1,j回退到0位置。
2、i=1,start=1,j=0去循环匹配。不匹配,break。start到2,j回退到0位置。
3、i=2,start=2,j=0去循环匹配。不匹配,start=4,j=2时不匹配,break。start回退到3,j回退到0位置。
4、i=3,start=3,j=0去循环匹配。不匹配,break。start到4,j回退到0位置。
5、i=4,start=4,j=0去循环匹配。不匹配,break。start到5,j回退到0位置。
5、i=5,start=5,j=0去循环匹配。匹配完成。(省略中间过程)。
从上述过程中可以看到,已经遍历过的位置会多次回退,无疑增加了时间复杂度。KMP算法过程和暴力遍历时相似的,只是在过程中对回退操作进行了优化,减少了回退。
了解KMP算法前,我们先了解一个定义:最长前后缀相等的长度(前缀和后缀相等的最大长度),对于字符串t,我们生成一个next数组,数组每个位置表示该位置之前的字符串中前缀和后缀相等的最大长度(规定:不能取到字符串最大长度,如果该位置前面没有字符串,最长前后缀相等的长度为-1(人为规定))。
比如上述字符串t=ababd,其next数组为 int[] next=new int[]{-1,0,0,1,2}。假设我们已经有了next数组,我们再看一下上面例子的匹配过程怎么加速?(后续会将next数组如何生成)
1、以0位置开头去匹配,当s来到start=4位置的e时,t位置来到j=4位置的d时,发现不匹配,我们检查next数组,发现4位置的最长前后缀相等的长度(next[4])是2,那么t位置回退到j=next[4]=2,继续开始比较;【为什么可以回退到这进行比较呢?因为s的前4个字符 abab,t的前4个字符 abab 已经比较过了,是相等的,而j=4时next[4]告诉我们当前位置前面字符串的最长前后缀相等长度是2,也就是说t[1]=s[start-1],t[0]=s[start-2],所以这两个位置就不需要再比较了,start就不需要进行回退了,j位置也可以只回退到next[4]位置。】其实此时的含义是,看以start-2位置开头的字符串是否可以匹配出t。
2、start=4,j=2位置开始比较,发现不匹配,此时j=2位置的最长前后缀相等的长度(next[2])是0,所以t的位置回退到j=next[2]=0;
3、start=4,j=0位置开始比较,发现不匹配,此时j已经为0,j无法再回退,所以satrt++;
4、start=5,j=0位置开始比较,匹配完成(后续过程省略)。
从上述过程我们可以看出,s的遍历位置没有回退。下面我们看一下KMP的代码。
public int KMP(String s,String t){if(s==null||n==null||s.length()<t.length()){return -1;}char[] ss=s.toCharArray();char[] tt=t.toCharArray();int N=tt.length;//获取t字符串的next数组 next[i]表示t字符串【i位置以前的最长前后缀相等长度】int[] next=getNextArray(t);int i=0;int j=0;while(i<ss.length){if(ss[i]==tt[j]){i++;j++;}else if(j>0){//t的位置可以回退,回退到当前位置的最长前后缀长度的下一个位置进行比较j=next[j];}else{//j=0&&ss[i]==tt[j]i++;}}return j==tt.length?i-j:-1;
}
关键问题来了,我们如何得到next数组呢?根据规定next[0]=-1,next[1]=0,next[2]=tt[0]==tt[1]?1:0。那么我们考虑一个普遍位置i(即考虑t字符串0-i-1位置字符串的前缀后缀相等情况),假设next[i-1]位置已经计算好了。如下图所示。那么就有以下几种情况:
1、tt[i-1]=tt[next[i-1]](tt[next[i-1]]即左侧的三角位置,next[i-1]标识的两段根据其定义知道相等),所以此时可得出 next[i]=next[i-1]+1;
2、tt[i-1]!=tt[next[i-1]],那如何寻找下一个比较位置呢?我们知道▲位置的next[▲]是该位置的最长前后缀相等长度,那么下一个比较位置就是★标识的位置,而★=next[▲]。以此类推,直到来到0位置,如果还不相等,那就代表i位置以前字符串的最长前后缀相等长度为0。
如此下去,我们得到字符串t的next数组。(最长前后缀相等长度数组)。下面请看代码。
public int[] getNextArray(String t){if (t.length() == 1) {return new int[]{-1};}if (t.length() == 2) {return new int[]{-1, 0};}char[] tt = t.toCharArray();int[] next = new int[t.length()];//规定值next[0] = -1;next[1] = 0;if (tt[0] == tt[1]) {next[2] = 1;}//从2位置开始计算int i = 2;int compareIndex=next[i-1];while(i<tt.length){if(tt[i-1]==tt[compareIndex]){//相等,next[i]就计算出来了,i++计算下一个位置,compareIndex++是next[i]的值//也是计算i+1位置时,第一个需要比较的位置,大家多画图就可以理解了next[i++]=compareIndex++;}else if(compareIndex>0){//计算下一个比较位置compareIndex=next[compareIndex];}else{//compareIndex==0&&tt[i-1]!=tt[compareIndex]next[i]=0;//求下一个位置i++;}}return next;
}
到此整个KMP算法就结束了,了解了原理后,代码还是很好写的。
相关文章:

Java-KMP字符串匹配算法
给两个字符串s和t,如何很快的知道s是否包含t(即t是否是s的子串)。暴力的方法,我们依次以s每个位置为头,去匹配t。 public int find(String s, String t) {char[] ss s.toCharArray();char[] tt t.toCharArray();int …...

Vue3使用vue-count-to数字滚动模块报错解决方案
小伙伴们是不是遇到了vue3项目使用vue-count-to出现报错的问题 报错如下: TypeError: Cannot read properties of undefined (reading _c) 这个错误信息具体是说没读取到_c的属性 具体不清楚是什么原因,排查还得去看源码,所以我们来解决&a…...

【高阶数据结构】线段树加乘(维护序列)详细解释乘与加懒标记
文章目录 1.题目[AHOI2009] 维护序列 2.懒标记处理先加后乘的形式1. 先加后乘的操作 先乘后加的形式2. 先乘后加的操作**乘法操作****加法操作** 懒标记的下传 3.代码 1.题目 题目来源:https://www.luogu.com.cn/problem/P2023 [AHOI2009] 维护序列 题目背景 老师交给小可可…...

replaceState和vue的router.replace删除query参数的区别
使用history.replaceState /*** 替换当前的 history state和url* param {(searchParams:URLSearchParams)>any} cb*/ export const replaceUrlSearch (cb) > {// 获取当前 URLconst url new URL(window.location.href)// 获取 URL 的查询参数const searchParams new …...

[USACO14JAN] Ski Course Rating G
题目大意 滑雪场用一个 N ∗ M N*M N∗M 的整数矩阵表示海拔高度,每个整数表示一个范围在 1 0 9 10^9 109 的高度。每个格子都可以滑到相邻的格子,爱好者们将会在雪场种尽情享受。有些格子被指定为起点,每个起点都要进行评级以帮助爱好者选…...

初步认识 Neo4j 图数据库
Neo4j 是一种高性能的图数据库管理系统,基于图论设计,能够高效地存储和查询复杂的关系数据。以下是关于 Neo4j 的详细介绍: 核心特性 数据模型: Neo4j 使用图数据模型,将数据以节点(Node)、关系…...

Qt中容器 QVector、QList、QSet和QMap 性能与用途比较
表格汇总: 容器存储结构随机访问性能插入/删除性能主要用途QVector连续存储的动态数组 O ( 1 ) O(1) O(1)末尾: O ( 1 ) O(1) O(1),中间: O ( n ) O(n) O(n)频繁随机访问,末尾元素的添加/删除QList优化存储࿰…...

ASP.NET Core - 依赖注入(四)
ASP.NET Core - 依赖注入(四) 4. ASP.NET Core默认服务5. 依赖注入配置变形 4. ASP.NET Core默认服务 之前讲了中间件,实际上一个中间件要正常进行工作,通常需要许多的服务配合进行,而中间件中的服务自然也是通过 Ioc…...
数学用语中 up to 的含义
1. 问题 在数学用语中,常见到“up to”这种用法, 但这种用法与我们常规情况下的用法不同,常令人困惑。 2. “等价关系”说明 已知两个数学对象 a 和 b,以及实数域R, • 当 a 和 b是通过 R 关联的࿰…...

Spring Boot + MyBatis-Flex 配置 ProxySQL 的完整指南
✅ Spring Boot MyBatis-Flex 配置 ProxySQL 的完整指南 下面是一个详细的教程,指导您如何在 Spring Boot 项目中使用 MyBatis-Flex 配置 ProxySQL 进行 读写分离 和 主从同步 的数据库访问。 🎯 目标 在 Spring Boot 中连接 ProxySQL。使用 MyBatis-…...

WEB攻防-通用漏洞_XSS跨站_权限维持_捆绑钓鱼_浏览器漏洞
目录 XSS的分类 XSS跨站-后台植入Cookie&表单劫持 【例1】:利用beef或xss平台实时监控Cookie等凭据实现权限维持 【例2】:XSS-Flash钓鱼配合MSF捆绑上线 【例3】:XSS-浏览器网马配合MSF访问上线 XSS的分类 反射型(非持久…...

人工智能任务20-利用LSTM和Attention机制相结合模型在交通流量预测中的应用
大家好,我是微学AI,今天给大家介绍一下人工智能任务20-利用LSTM和Attention机制相结合模型在交通流量预测中的应用。交通流量预测在现代城市交通管理中是至关重要的一环,它对优化交通资源分配以及提升道路通行效率有着不可忽视的意义。在实际…...

Day04-后端Web基础——Maven基础
目录 Maven课程内容1. Maven初识1.1 什么是Maven?1.2 Maven的作用1.2.1 依赖管理1.2.2 项目构建1.2.3 统一项目结构 2. Maven概述2.1 Maven介绍2.2 Maven模型2.2.1 构建生命周期/阶段(Build lifecycle & phases)2.2.2 项目对象模型 (Project Object Model)2.2.3 依赖管理模…...

Hive SQL必刷练习题:留存率问题
首次登录算作当天新增,第二天也登录了算作一日留存。可以理解为,在10月1号登陆了。在10月2号也登陆了,那这个人就可以算是在1号留存 今日留存率 (今日登录且明天也登录的用户数) / 今日登录的总用户数 * 100% 解决思…...

虚拟同步机(VSG)Matlab/Simulink仿真模型
虚拟同步机控制作为原先博文更新的重点内容,我将在原博客的基础上,再结合近几年的研究热点对其内容进行更新。Ps:VSG相关控制方向的simulink仿真模型基本上都搭建出来了,一些重要的控制算法也完成了实验验证。 现在搭建出来的虚拟…...

单头注意力机制(SHSA)详解
定义与原理 单头注意力机制是Transformer模型中的核心组件之一,它通过模拟人类注意力选择的过程,在复杂的输入序列中识别和聚焦关键信息。这种方法不仅提高了模型的性能,还增强了其解释性,使我们能够洞察模型决策的原因。 单头注意力机制的工作流程主要包括以下几个步骤:…...

【漏洞分析】DDOS攻防分析
0x00 UDP攻击实例 2013年12月30日,网游界发生了一起“追杀”事件。事件的主角是PhantmL0rd(这名字一看就是个玩家)和黑客组织DERP Trolling。 PhantomL0rd,人称“鬼王”,本名James Varga,某专业游戏小组的…...

JavaScript动态渲染页面爬取之Splash
Splash是一个 JavaScript渲染服务,是一个含有 HTTP API的轻量级浏览器,它还对接了 Python 中的 Twisted 库和 OT库。利用它,同样可以爬取动态渲染的页面。 功能介绍 利用 Splash,可以实现如下功能: 异步处理多个网页的渲染过程:获取渲染后…...

慧集通(DataLinkX)iPaaS集成平台-系统管理之UI库管理、流程模板
UI库管理 UI库管理分为平台级和自建两种,其中平台级就是慧集通平台自己内置的一些ui库所有客户均可调用,自建则是平台支持使用者自己根据规则自己新增对应的UI库。具体界面如下: 自建UI库新增界面: 注:平台级UI库不支…...

OpenCV相机标定与3D重建(59)用于立体相机标定的函数stereoCalibrate()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 标定立体相机设置。此函数找到两个相机各自的内参以及两个相机之间的外参。 cv::stereoCalibrate 是 OpenCV 中用于立体相机标定的函数。它通过一…...

摄像头模块在狩猎相机中的应用
摄像头模块是狩猎相机的核心组件,在狩猎相机中发挥着关键作用,以下是其主要应用: 图像与视频拍摄 高清成像:高像素的摄像头模块可确保狩猎相机拍摄出清晰的图像和视频,能够捕捉到动物的毛发纹理、行为细节及周围环境的…...

ruoyi-cloud docker启动微服务无法连接nacos,Client not connected, current status:STARTING
ruoyi-cloud docker启动微服务无法连接nacos,Client not connected, current status:STARTING 场景 当使用sh deploy.sh base来安装mysql、redis、nacos环境后,紧接着使用sh deploy.sh modules安装微服务模块,会发现微服务无法连接nacos的情…...

代码随想录算法训练营第三十四天-动态规划-63. 不同路径II
本题与上一题区别不大但由于存在障碍格,导致在计算路径值时,要多考虑一些情况 比如,障碍格在开始与结束位置时,路径直接返回0障碍格在初始的首行与首列时,设置初始值要不同在计算dp值时,要先判断当前格是不…...

在一个sql select中作多个sum并分组
有表如下; 单独的对某一个列作sum并分组,结果如下; 对于表的第7、8行,num1都有值,num2都是null,对num2列作sum、按id分组,结果在id为4的行会显示一个null; 同时对2个列作sum&#x…...

家用电路频繁跳闸的原因及解决方法!
家庭电路跳闸是一个常见的用电故障,正确理解跳闸原因并采取恰当的处理方法,不仅能够及时恢复供电,更能预防潜在的安全隐患。 一、问题分析 断路器跳闸通常是电路保护装置在发现异常时的自动保护行为,主要出现以下几种情况…...

我的年度总结
这一年的人生起伏:从曙光到低谷再到新的曙光 其实本来没打算做年度总结的,无聊打开了帅帅的视频,结合自己最近经历的,打算简单聊下。因为原本打算做的内容会是一篇比较丧、低能量者的呻吟。 实习生与创业公司的零到一 第一段工…...

ASP.NET Core 多环境配置
一、开篇明义:多环境配置的重要性 在ASP.NET Core 开发的广袤天地中,多环境配置堪称保障应用稳定运行的中流砥柱。想象一下,我们精心打造的应用,要在开发、测试、预发布和生产等截然不同的环境中穿梭自如。每个环境都如同一个独特…...

docker 安装mongodb
1、先获取mongodb镜像 docker pull mongo:4.2 2、镜像拉取完成后,运行mongodb容器 docker run \ -d \ --name mongo \ --restartalways \ --privilegedtrue \ -p 27017:27017 \ -v /home//mongodb/data:/data/db \ mongo:4.2 --auth 3、mongodb服务配置 如上图&…...

完整地实现了推荐系统的构建、实验和评估过程,为不同推荐算法在同一数据集上的性能比较提供了可重复实验的框架
{"cells": [{"cell_type": "markdown","metadata": {},"source": ["# 基于用户的协同过滤算法"]},{"cell_type": "code","execution_count": 1,"metadata": {},"ou…...

DRV8311三相PWM无刷直流电机驱动器
1 特性 • 三相 PWM 电机驱动器 – 三相无刷直流电机 • 3V 至 20V 工作电压 – 24V 绝对最大电压 • 高输出电流能力 – 5A 峰值电流驱动能力 • 低导通状态电阻 MOSFET – TA 25C 时,RDS(ON) (HS LS) 为210mΩ(典型值) • 低功耗睡眠模式…...