当前位置: 首页 > 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 中用于立体相机标定的函数。它通过一…...

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

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

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...