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

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=4j=4时,不匹配,break。start回退到1j回退到0位置

2、i=1,start=1,j=0去循环匹配。不匹配,break。start到2,j回退到0位置。

3、i=2,start=2,j=0去循环匹配。不匹配,start=4j=2时不匹配,break。start回退到3j回退到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&#xff0c;如何很快的知道s是否包含t&#xff08;即t是否是s的子串&#xff09;。暴力的方法&#xff0c;我们依次以s每个位置为头&#xff0c;去匹配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出现报错的问题 报错如下&#xff1a; TypeError: Cannot read properties of undefined (reading _c) 这个错误信息具体是说没读取到_c的属性 具体不清楚是什么原因&#xff0c;排查还得去看源码&#xff0c;所以我们来解决&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 的整数矩阵表示海拔高度&#xff0c;每个整数表示一个范围在 1 0 9 10^9 109 的高度。每个格子都可以滑到相邻的格子&#xff0c;爱好者们将会在雪场种尽情享受。有些格子被指定为起点&#xff0c;每个起点都要进行评级以帮助爱好者选…...

初步认识 Neo4j 图数据库

Neo4j 是一种高性能的图数据库管理系统&#xff0c;基于图论设计&#xff0c;能够高效地存储和查询复杂的关系数据。以下是关于 Neo4j 的详细介绍&#xff1a; 核心特性 数据模型&#xff1a; Neo4j 使用图数据模型&#xff0c;将数据以节点&#xff08;Node&#xff09;、关系…...

Qt中容器 QVector、QList、QSet和QMap 性能与用途比较

表格汇总&#xff1a; 容器存储结构随机访问性能插入/删除性能主要用途QVector连续存储的动态数组 O ( 1 ) O(1) O(1)末尾&#xff1a; O ( 1 ) O(1) O(1)&#xff0c;中间&#xff1a; O ( n ) O(n) O(n)频繁随机访问&#xff0c;末尾元素的添加/删除QList优化存储&#xff0…...

ASP.NET Core - 依赖注入(四)

ASP.NET Core - 依赖注入&#xff08;四&#xff09; 4. ASP.NET Core默认服务5. 依赖注入配置变形 4. ASP.NET Core默认服务 之前讲了中间件&#xff0c;实际上一个中间件要正常进行工作&#xff0c;通常需要许多的服务配合进行&#xff0c;而中间件中的服务自然也是通过 Ioc…...

数学用语中 up to 的含义

1. 问题 在数学用语中&#xff0c;常见到“up to”这种用法&#xff0c; 但这种用法与我们常规情况下的用法不同&#xff0c;常令人困惑。 2. “等价关系”说明 已知两个数学对象 a 和 b&#xff0c;以及实数域R&#xff0c; • 当 a 和 b是通过 R 关联的&#xff0…...

Spring Boot + MyBatis-Flex 配置 ProxySQL 的完整指南

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

WEB攻防-通用漏洞_XSS跨站_权限维持_捆绑钓鱼_浏览器漏洞

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

人工智能任务20-利用LSTM和Attention机制相结合模型在交通流量预测中的应用

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

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必刷练习题:留存率问题

首次登录算作当天新增&#xff0c;第二天也登录了算作一日留存。可以理解为&#xff0c;在10月1号登陆了。在10月2号也登陆了&#xff0c;那这个人就可以算是在1号留存 今日留存率 &#xff08;今日登录且明天也登录的用户数&#xff09; / 今日登录的总用户数 * 100% 解决思…...

虚拟同步机(VSG)Matlab/Simulink仿真模型

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

单头注意力机制(SHSA)详解

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

【漏洞分析】DDOS攻防分析

0x00 UDP攻击实例 2013年12月30日&#xff0c;网游界发生了一起“追杀”事件。事件的主角是PhantmL0rd&#xff08;这名字一看就是个玩家&#xff09;和黑客组织DERP Trolling。 PhantomL0rd&#xff0c;人称“鬼王”&#xff0c;本名James Varga&#xff0c;某专业游戏小组的…...

JavaScript动态渲染页面爬取之Splash

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

慧集通(DataLinkX)iPaaS集成平台-系统管理之UI库管理、流程模板

UI库管理 UI库管理分为平台级和自建两种&#xff0c;其中平台级就是慧集通平台自己内置的一些ui库所有客户均可调用&#xff0c;自建则是平台支持使用者自己根据规则自己新增对应的UI库。具体界面如下&#xff1a; 自建UI库新增界面&#xff1a; 注&#xff1a;平台级UI库不支…...

OpenCV相机标定与3D重建(59)用于立体相机标定的函数stereoCalibrate()的使用

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

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

论文阅读:Matting by Generation

今天介绍一篇关于 matting 抠图的文章&#xff0c;抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法&#xff0c;已经有很多的工作和这个任务相关。这两年 diffusion 模型很火&#xff0c;大家又开始用 diffusion 模型做各种 CV 任务了&am…...

【1】跨越技术栈鸿沟:字节跳动开源TRAE AI编程IDE的实战体验

2024年初&#xff0c;人工智能编程工具领域发生了一次静默的变革。当字节跳动宣布退出其TRAE项目&#xff08;一款融合大型语言模型能力的云端AI编程IDE&#xff09;时&#xff0c;技术社区曾短暂叹息。然而这一退场并非终点——通过开源社区的接力&#xff0c;TRAE在WayToAGI等…...

ubuntu中安装conda的后遗症

缘由: 在编译rk3588的sdk时&#xff0c;遇到编译buildroot失败&#xff0c;提示如下&#xff1a; 提示缺失expect&#xff0c;但是实测相关工具是在的&#xff0c;如下显示&#xff1a; 然后查找借助各个ai工具&#xff0c;重新安装相关的工具&#xff0c;依然无解。 解决&am…...

鸿蒙Navigation路由导航-基本使用介绍

1. Navigation介绍 Navigation组件是路由导航的根视图容器&#xff0c;一般作为Page页面的根容器使用&#xff0c;其内部默认包含了标题栏、内容区和工具栏&#xff0c;其中内容区默认首页显示导航内容&#xff08;Navigation的子组件&#xff09;或非首页显示&#xff08;Nav…...