leetcode刷题总结——字符串匹配

KMP(字符串匹配算法)

主串或目标串:比较长的,我们就是在它里面寻找子串是否存在;

子串或模式串:比较短的。

前缀:字符串A和B,A = B+S,S非空,则B为A的前缀。

后缀:A = S+B,S非空,则B为A的后缀。

PMT:前缀集合和后缀集合的交集中,最长前缀的长度。

部分匹配表:PMT值集合,字符串的所有前缀的PMT值。
在这里插入图片描述

当出现失配的字符时,我们原来的暴力算法需要将目标串逐个后移,这个过程其实就是拿已经匹配部分的前缀去逐个匹配后缀。如果我们能够知道每一个位置i处,S[0:i]中已经和后缀匹配的前缀,那么我们是不是就可以直接将前缀和后缀对齐,进而跳过了中间一些字符,然后直接去比较模式串i+1处的字符呢?答案是肯定的。

KMP.drawio.png

图中绿色块,就是构建next数组过程中,随着遍历的深入,前缀和后缀的匹配情况。

其实,我们换一个方向去思考或许更容易:

例如红色A处失配,那么我们就将目标串往后移动,我们希望移动到模式串的前缀当前已经遍历到的目标串的后缀匹配字符最多的地方。

我们需要一个next数组记录目标串的当前位置失配时,模式串应该转跳的位置。

next数组与模式串对应。并且next[0] = -1,表示第一个字符没有匹配的前后缀,如果在0位置失配,只能将目标串后移一位,去和模式串的第二位进行匹配。

next数组中如果某一个元素值为-1,其实就是表示模式串当前位置没有匹配的前缀,如果在这个位置失配,那么应该直接将目标串的第一位和模式串的下一位比较。

next数组的构造,是通过模式串自己的前缀和后缀匹配进行的。

next[0]=-1;
// 初始化next数组
int i=0,j=-1;//i指向目标串,j指向模式串
while(i<ch.length){if(j==-1){// j=-1,说明,与i匹配的地方是空,那么也就说明,模式串已经到开头了// 但是还是和目标串不匹配// abab bab b和a不匹配,我们应该将i后移再和j匹配。i+=1;j+=1;}if(ch[i]==ch[j]){i+=1;j+=1;// 当前位置匹配,next[i]的值等于当前位置之前的字符串的PMTnext[i]=j;}else{// 当前位置不匹配,对模式串进行转跳,// next[j]表示如果在当前位置失配,就应该将模式串的索引转跳到next[j]位置,继续匹配j=next[j];}
}

next[i]数组的值表示匹配串的i位置失配了,那么就应该拿模式串的前缀继续和当前位置匹配,即转跳到next[i]位置,继续判断是否匹配。

public static int KMP(String Str,String Sub,int pos){if (Str == null || Sub == null){return -1;}int i = pos, j = 0;int[] next = new int[Sub.length()];getNext(next,Sub);while(i < Str.length() && j < Sub.length()){if (j == -1 || Str.charAt(i) == Sub.charAt(j)){i++;j++;}else {j = next[j];}}if (j >= Sub.length()){return i-j;}else {return -1;}
}
public static void getNext(int[] next,String sub){next[0] = -1;next[1] = 0;int i = 2,k = 0;while(i < next.length){if (k ==- 1 || sub.charAt(k) == sub.charAt(i-1)){next[i] = k+1;i++;k++;}else {k = next[k];}}
}

示例一

459. 重复的子字符串

/*** 方法一:枚举法,由于子串至少有两个,因此,我们枚举子串的长度1<=k<=n//2;* 方法二:KMP算法,首先先证明一个原理* 假设s的子串为c,且为4个,那么s可以表示为     ccccc* 如果我们将第一个c移动到末尾,那么应该还可以组成s。* 基于这个原理,我们将s复制一份,变成 ss,如果我们删除ss的第一个字符和最后一个字符* 如果s存在子串c,那么,ss经过删除前后两个字符后,中间部分一定还存在和s匹配的字符串*/

示例二

1392. 最长快乐前缀

/*** 思路:kmp算法,首先需要得到字符串s的next数组* 然后,根据题意可知,快乐前缀是和后缀匹配的。那么我们就需要知道,next数组中最后一个位置的数值pos* pos表示,s最后一个数对应的转跳位置,然后,我们需要进一步比较s[pos]是否等于s[-1]:*   a. 等于,则找到了最长的快乐前缀;*   b. 不等于,pos位置失配,继续转跳pos=next[pos];* 直到s[pos]==s[-1]或者pos==-1为止。*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/45894.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java--数据结构】二叉树

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 树结构 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合 注意&#xff1a;树形结构中&#xff0c;子…

【linux高级IO(三)】初识epoll

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; Linux高级IO 1. 前言2. 初识e…

STM32 HRTIM生成PWM时遇到无法输出PWM脉冲波形问题

在使用HRTIM生成PWM时&#xff0c;当把周期寄存器更新的设置放到while循环中时&#xff0c;无法输出PWM脉冲波形&#xff0c;即使增加计数延时也无法输出&#xff0c;最终只能放到中断函数中执行后期寄存器值更新才能够生成PWM脉冲波形。

主流大数据调度工具DolphinScheduler之数据ETL流程

今天给大家分享主流大数据调度工具DolphinScheduler&#xff0c;以及数据的ETL流程。 一&#xff1a;调度工具DS 主流大数据调度工具DolphinScheduler&#xff0c; 其定位&#xff1a;解决数据处理流程中错综复杂的依赖关系 任务支持类型&#xff1a;支持传统的shell任务&a…

冷却塔由那些配件组成

1、淋水填料 将需要冷却的水&#xff08;热水&#xff09;多次溅洒成水滴或形成水膜&#xff0c;以增加水和空气的接触面积和时间&#xff0c;促进水和空气的热交换。 填料在开式横流冷却塔的作用是增加循环水与空气的接触面积&#xff0c;并延长冷却水停留在空气中的时间&am…

LabVIEW工业设备姿态监测系统

开发了一种基于LabVIEW的工业设备姿态监测系统&#xff0c;针对现有监测设备在适应性和反应时间上的不足&#xff0c;采用了LabVIEW软件和STM32微控制器&#xff0c;通过高精度姿态传感器实现了对设备姿态的快速准确监测&#xff0c;大大提高了工业作业的安全与效率。 项目背景…

C++深度解析教程笔记9-静态成员变量,静态成员函数,二阶构造,友元,函数重载,操作符重载

C深度解析教程笔记9 第25课 - 类的静态成员变量实验-数对象个数&#xff08;失败&#xff09;实验-静态变量小结 第26课 - 类的静态成员函数实验-修改对象的静态变量数值实验-利用静态成员函数实验-静态变量静态函数实现统计对象个数小结 第27课 - 二阶构造模式实验-初始化是否…

百度人脸识别Windows C++离线sdk C#接入

百度人脸识别Windows C离线sdk C#接入 目录 说明 设计背景 • 场景特点&#xff1a; • 客户特点&#xff1a; • 核心需求&#xff1a; SDK 包结构 效果 代码 说明 自己根据SDK封装了动态库&#xff0c;然后C#调用。 功能接口 设计背景 • 场景特点&#xff1a; -…

支持前端路由权限和后端接口权限的企业管理系统模版

一、技术栈 前端&#xff1a;iview-admin vue 后端&#xff1a;springboot shiro 二、基于角色的权限控制 1、路由权限 即不同角色的路由访问控制 2、菜单权限 即不同角色的菜单列表展示 3、按钮权限 即不同角色的按钮展示 4、接口权限 即不同角色的接口访问控制 三…

数字化时代的生产革新:数字孪生平台如何助力新质生产力

一.新质生产力 在当今快速发展的科技和信息时代&#xff0c;企业和组织在提高生产效率和质量方面面临着越来越多的挑战和机遇。新质生产力的概念应运而生&#xff0c;强调通过创新和技术进步&#xff0c;不仅提升生产的数量和速度&#xff0c;更重要的是优化生产方式、改善产品…

leetcode热题100.分割等和子集(动态规划)

分割等和子集 Problem: 416. 分割等和子集 思路 我选择使用动态规划的方法来解题。我们需要判断是否可以将数组分割成两个子集&#xff0c;使得这两个子集的和相等。这个问题可以转化为在数组中找到一个子集&#xff0c;使得其和等于数组总和的一半。 解题过程 首先&#xf…

图——图的应用02最短路径(Dijkstra算法与Floyd算法详解),拓扑排序及关键路径

前面介绍了图的应用——01最小生成树章节&#xff0c;大家可以通过下面的链接学习&#xff1a; 图——图的应用01最小生成树&#xff08;Prim算法与Kruskal算法详解&#xff09; 今天就讲一下图的其他应用——最短路径&#xff0c;拓扑排序及关键路径。 目录 一&#xff0c…

成都亚恒丰创教育科技有限公司 【插画猴子:笔尖下的灵动世界】

在浩瀚的艺术海洋中&#xff0c;每一种创作形式都是人类情感与想象力的独特表达。而插画&#xff0c;作为这一广阔领域中的璀璨明珠&#xff0c;以其独特的视觉语言和丰富的叙事能力&#xff0c;构建了一个又一个令人遐想连篇的梦幻空间。成都亚恒丰创教育科技有限公司 在众多插…

Linux——进程概念详解

一、进程的基本概念 在给进程下定义之前&#xff0c;我们先了解一下进程&#xff1a; 我们在编写完代码并运行起来时&#xff0c;在我们的磁盘中会形成一个可执行文件&#xff0c;当我们双击这个可执行文件时&#xff08;程序时&#xff09;&#xff0c;这个程序会加载到内存…

动手学深度学习6.3 填充和步幅-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;填充和步幅_哔哩哔哩_bilibili 代码实现_哔哩哔哩_bilibili 本节教材地址&#xff1a;6.3. 填充和…

自建Web网站部署——案例分析

作者主页: 知孤云出岫 目录 作者主页:如何自建一个Web网站一、引言二、需求分析三、技术选型四、开发步骤1. 项目初始化初始化前端初始化后端 2. 前端开发目录结构示例代码App.jsHome.js 3. 后端开发目录结构示例代码app.jsproductRoutes.jsProduct.js 4. 前后端连接安装axio…

泛微e-cology WorkflowServiceXml SQL注入漏洞(POC)

漏洞描述&#xff1a; 泛微 e-cology 是泛微公司开发的协同管理应用平台。泛微 e-cology v10.64.1的/services/接口默认对内网暴露&#xff0c;用于服务调用&#xff0c;未经身份认证的攻击者可向 /services/WorkflowServiceXml 接口发送恶意的SOAP请求进行SQL注入&#xff0c;…

使用JS和CSS制作的小案例(day二)

一、写在开头 本项目是从github上摘取&#xff0c;自己练习使用后分享&#xff0c;方便登录github的小伙伴可以看本篇文章 50项目50天​编辑https://github.com/bradtraversy/50projects50dayshttps://github.com/bradtraversy/50projects50days有兴趣的小伙伴可以自己去gith…

面向对象七大原则

学习目标 了解面向对象七大原则基本概念。 在之后实践应用中&#xff0c;要给予七大原则去设计程序。 为什么有七大原则 七大原则总体要实现的目标是&#xff1a; 高内聚、低耦合。 使程序模块的可重复性、移植性增强。 高内聚低耦合 从类角度来看&#xff0c;高内聚低…

如何在Linux上部署Ruby on Rails应用程序

在Linux上部署Ruby on Rails应用程序是一个相对复杂的过程&#xff0c;需要按照一系列步骤进行。下面是一个基本的部署过程&#xff0c;涵盖了从安装所需软件到部署应用程序的所有步骤。 安装必要的软件 在部署Ruby on Rails应用程序之前&#xff0c;需要确保Linux系统上安装了…