代码算法训练营day9 | 28. 实现 strStr() 、459.重复的子字符串

news2024/12/23 8:56:38

day9:

  • 28. 实现 strStr()
      • KMP的主要应用:
      • 什么是前缀表:
        • 前缀表是如何记录的:
      • 如何计算前缀表:
      • 构造next数组:
        • 1、初始化
        • 2、处理前后缀不相同的情况
        • 3、处理前后缀相同的情况
      • 代码:
  • 459.重复的子字符串(先不做了,)

28. 实现 strStr()

题目链接
状态:KMP不太懂
文档:programmercarl.com

思路:
KMP的经典思想就是:当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。

KMP的主要应用:

KMP主要应用在字符串匹配上。
KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。

什么是前缀表:

next数组就是一个前缀表(prefix table)
前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。

举个例子:(在文本串中查找是否存在模式串)
文本串:aa b aa baafa — 模式串:aa b aa f
可以看出,文本串中第六个字符b 和 模式串的第六个字符f,不匹配了。如果暴力匹配,发现不匹配,此时就要从头匹配了。
但如果使用前缀表,就不会从头匹配,而是从上次已经匹配的内容开始匹配。

文本串中的aabaa已经和模式串中的aabaa匹配好了,只有最后一个字符不匹配
那么就要从上次已经匹配好的内容开始匹配,上次和模式串中的 f 前的aa匹配好了的是文本串中的b,所以从模式串中第三个字符b继续开始匹配。

前缀表是如何记录的:

首先要知道前缀表的任务是当前位置匹配失败,找到之前已经匹配上的位置,再重新匹配,此也意味着在某个字符失配时,前缀表会告诉你下一步匹配中,模式串应该跳到哪个位置。

那么什么是前缀表:记录下标 i 之前(包括i)的字符串中,有多大长度的相同前缀后缀。

如何计算前缀表:

前缀表
注意字符串的前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串
可以看出模式串与前缀表对应位置的数字表示的就是:下标 i 之前(包括i)的字符串中,有多大长度的相同前缀后缀。

找到的不匹配的位置, 那么此时我们要看它的前一个字符的前缀表的数值是多少。
为什么要前一个字符的前缀表的数值呢,因为要找前面字符串的最长相同的前缀和后缀。所以要看前一位的 前缀表的数值。
前一个字符的前缀表的数值是几, 所以把下标移动到下标为几的位置继续匹配。

next数组既可以就是前缀表,也可以是前缀表统一减一(右移一位,初始位置为-1)。

构造next数组:

我们定义一个函数getNext来构建next数组,函数参数为指向next数组的指针,和一个字符串。 代码如下:

void getNext(int* next, const string& s)

构造next数组其实就是计算模式串s,前缀表的过程。 主要有如下三步:

  1. 初始化
  2. 处理前后缀不相同的情况
  3. 处理前后缀相同的情况
1、初始化

定义两个指针 i 和 j,j 指向前缀末尾位置,i 指向后缀末尾位置。
然后还要对next数组进行初始化赋值,如下:

int j = -1;
next[0] = j;

next[i] 表示 i(包括i)之前最长相等的前后缀长度(其实就是j)

2、处理前后缀不相同的情况

因为j初始化为-1,那么i就从1开始,进行s[i] 与 s[j+1]的比较。
为什么是 i 和 j+1 去比较呢?既然前缀表统一减一了,那么回退的时候也会多回退1,所以就要在 j 上下功夫了,让 j+1,每次比较的时候都比较 j 的后一位。
遍历模式串s的循环下标i 要从 1开始,代码如下:

for (int i = 1; i < s.size(); i++) {

如果 s[i] 与 s[j+1]不相同,也就是遇到 前后缀末尾不相同的情况,就要向前回退。
怎么回退呢?
next[j]就是记录着j(包括j)之前的子串的相同前后缀的长度。
那么 s[i] 与 s[j+1] 不相同,就要找 j+1前一个元素在next数组里的值(就是next[j])。
所以,处理前后缀不相同的情况代码如下:

while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
    j = next[j]; // 向前回退
}
3、处理前后缀相同的情况

如果 s[i] 与 s[j + 1] 相同,那么就同时向后移动i 和j,说明找到了相同的前后缀,
所有情况处理结束后,还要将j(前缀的长度)赋给next[i], 因为next[i]要记录相同前后缀的长度。

if (s[i] == s[j + 1]) { // 找到相同的前后缀
    j++;
}
next[i] = j;

最后整体构建next数组的函数代码如下:

void getNext(int* next, const string& s){
    int j = -1;
    next[0] = j;
    for(int i = 1; i < s.size(); i++) { // 注意i从1开始
        while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
            j = next[j]; // 向前回退
        }
        if (s[i] == s[j + 1]) { // 找到相同的前后缀
            j++;
        }
        next[i] = j; // 将j(前缀的长度)赋给next[i]
    }
}

代码:

class Solution {
public:
    //创建next数组 整体-1
    void getNext(int* next,string& s)
    {
        //初始化(后缀i,前缀j,next数组)
        int j = -1;
        next[0] = j;
        //i不能=0,因为还要和j进行比较
        for(int i=1;i<s.size();i++)
        {
            //前后缀不相等
            while(j >= 0 && s[i] != s[j+1])
            {
                //j向前一个next的值进行回退
                j = next[j];
            }
            //前后缀相等
            if(s[i] == s[j+1])
            {
                j++; //j向前走一位,同时i也向前走一位
            }
            //更新next值
            next[i] = j; //因为j已经++了,所以已经表示相对应的串的长度了
        }
    }

    int strStr(string haystack, string needle) {
        if(needle.size() ==0)
        {
            return 0;
        }
        int next[needle.size()];
        getNext(next,needle); //获取needle的next数组
        //在文本串s里 找是否出现过模式串t
        int j = -1; //因为next数组里记录的起始位置为-1
        //i是从0开始的,因为要从头比
        for(int i = 0;i<haystack.size();i++)
        {
            //如果不匹配
            while(j >= 0 && haystack[i] != needle[j+1])
            {
                //j>=0才行,不然next[j]就是无效数据了
                j = next[j];
            }
            //匹配上了
            if(haystack[i] == needle[j+1]) j++;
            if(j == needle.size()-1) //比的是j+1 j++后就是j+1的位置
                return (i-needle.size()+1);
        }
        return -1;
    }
};

459.重复的子字符串(先不做了,)

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

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

相关文章

P1303 A*B Problem(高精度乘法)

题目描述&#xff1a; 图解&#xff1a; 此图来源于ACwing一位大佬的题解 AC代码&#xff1a; #include<iostream> #include<vector>using namespace std;vector<int> mul(vector<int> &A,vector<int> &B) {vector<int> C(A.…

C#创建第一个PIESDK模版的项目

目录 环境配置创建项目方式 环境配置 1软件安装 通过安装光盘或者U盘等介质读取PIE软件的安装程序和使用文档。程序安装过程比较简单&#xff0c;软件本身不借助与任何第三方程序&#xff0c;直接双击安装程序【PIESDK.Net_V6.3_Windows_X64.exe】安装文件&#xff0c;即可安装…

Java Swing游戏开发学习12

内容来自RyiSnow视频讲解 这一节讲的是实现游戏中的NPC(Non Player Character)非玩家角色。 添加了一个老人NPC&#xff0c;一个简单的AI&#xff08;人工智能&#xff09;拄着拐杖四处走。老人与树木、玩家的碰撞检测。 NPC四处走动 实现NPC四处走动 一开始&#xff0c;每一…

掌握Go语言:深入encoding/gob包的高效数据序列化

掌握Go语言&#xff1a;深入encoding/gob包的高效数据序列化 引言理解Gob和它的使用场景Gob的概念和设计目标Gob的适用场景和优势 开始使用Gob基本的Gob编码和解码示例代码编码&#xff08;序列化&#xff09;解码&#xff08;反序列化&#xff09; Gob编码高级应用自定义类型的…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Tabs)

通过页签进行内容视图切换的容器组件&#xff0c;每个页签对应一个内容视图。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 该组件从API Version 11开始默认支持安全区避让特性(默认值为&#x…

炸裂!全球首个AI程序员!

近年来&#xff0c;人工智能&#xff08;AI&#xff09;在多个领域取得了显著进展&#xff0c;不断拓展其能力边界。一个引人注目的突破是全球首个AI程序员——Devin的诞生。 这一创新不仅展示了AI技术的快速进步&#xff0c;而且对软件开发领域和未来的工作场景产生了深远的影…

【重新定义matlab强大系列十八】Matlab深度学习长短期记忆 (LSTM) 网络生成文本

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

嵌入式开发基础总结

学习目标 1.了解嵌入式开发 2.开发环境的搭建 3.Linux操作系统的基本操作 一、了解嵌入式开发 以应用为中心&#xff0c;以计算机技术为基础&#xff0c;软硬件可裁剪&#xff0c;适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。 1.嵌入式可以干…

【C++算法模板】预处理算法:一维前缀和、二维前缀和总结,详解带例题

文章目录 0&#xff09;概述1&#xff09;一维前缀和2&#xff09;二维前缀和 0&#xff09;概述 因为前缀和这个板子的推导比较简单&#xff0c;因此本博客重点在于知识点归纳而不在于证明 1&#xff09;一维前缀和 一维数组的前缀和计算公式&#xff1a; s [ i ] ∑ i 1…

SVM-支持向量机实验分析(软硬间隔,线性核,高斯核)

目录 一、前言 二、实验 0. 导入包 1. 支持向量机带来的效果 2. 软硬间隔 3. 非线性支持向量机 4. 核函数变换 线性核 高斯核 对比不同的gamma值对结果的影响 一、前言 学习本文之前要具有SVM支持向量机的理论知识&#xff0c;可以参考支持向量机&#xff08;Support Vector …

win10 配置 oh-my-posh

win10 配置 oh-my-posh 0. 前置1. 安装1.1. 软件1.2. 字体1.3. 激活1.3.1. Git Bash1.3.2. PowerShell 2. 配置2.1. 效果2.2. 说明2.3. 其他2.3.1. 新版PowerShell2.3.2 conda问题 0. 前置 这个东西毕竟是个&#xff0c;命令行美化工具&#xff0c;所以需要先有一个命令行&…

从MFC迁移到wxWidgets视频教程

犹他州C程序员团队发布了一个关于从MFC迁移到wxWidgets的新视频&#xff08;需要科学上网&#xff09;&#xff0c;并附带了一个包含详细步骤说明的要点。 希望这对那些希望使其现有的MFC应用程序可移植&#xff0c;或者只是希望切换到维护更活跃的框架的人来说会有所帮助。 附…

NPM 仓库的超集 JSR 来了!

引言 今天在 Deno 博客中看到了一篇文章&#xff0c;介绍了一个叫 JSR 的包管理注册中心&#xff0c;简单尝试了一下觉得还不错&#xff0c;本文将结合原文章和个人体验对 JSR 进行一个详细的介绍。 在现如今的前端开发中&#xff0c;包管理注册中心 (如 npmjs.com) 扮演着至…

2024人工智能四大趋势→

2023年&#xff0c;世人见证了ChatGPT在全球范围的大火。以生成式人工智能为代表的新一代人工智能问世&#xff0c;改变了人工智能&#xff08;AI&#xff09;技术与应用的发展轨迹&#xff0c;加速了人与AI的互动进程&#xff0c;是人工智能发展史上的新里程碑。2024年&#x…

NCV8705MTADJTCG稳压器芯片中文资料规格书PDF数据手册引脚图图片价格功能

产品概述&#xff1a; NCV8705 是一款低噪音、低功耗和低泄漏线性电压稳压器。该器件具有卓越的噪音和 PSRR 规格&#xff0c;适用于使用视频接收器、成像传感器、音频处理器或需要外部洁净电源的任何部件的产品。NCV8705 使用创新的自适应接地电流电路 可确保轻负载调节下的超…

2024.4.17周报

目录 摘要 Abstract 文献阅读&#xff1a;耦合时间和非时间序列模型模拟城市洪涝区洪水深度 现有问题 提出方法 创新点 XGBoost和LSTM耦合模型 XGBoost算法 ​编辑 LSTM&#xff08;长短期记忆网络&#xff09; 耦合模型 研究实验 数据集 评估指标 研究目的 洪水…

计算机操作系统(四)

存储器管理 计算机的存储层次至少有三层&#xff0c;分别是寄存器、内存、外存。还可以根据具体功能划分为寄存器、高速缓存、内存、磁盘缓存、固定磁盘、可移动存储。 其中&#xff0c;寄存器、高速缓存、内存和磁盘缓存均属于操作系统存储管理的管辖范畴,断电后信息不再存在…

“AI巨浪:ChatGPT等大模型重塑科研与创新的未来!“

AI大模型引领未来智慧科研暨ChatGPT在地学、GIS、气象、农业、生态、环境等领域中的应用 以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮&#xff0c;可以面向科研选题、思维导图、数…

第十三篇:复习Java面向对象

文章目录 一、面向对象的概念二、类和对象1. 如何定义/使用类2. 定义类的补充注意事项 三、面向对象三大特征1. 封装2. 继承2.1 例子2.2 继承类型2.3 继承的特性2.4 继承中的关键字2.4.1 extend2.4.2 implements2.4.3 super/this2.4.4 final 3. 多态4. 抽象类4.1 抽象类4.2 抽象…

Epuck2机器人固件更新及IP查询

文章目录 前言一、下载固件更新软件包&#xff1a;二、查询机器人在局域网下的IP 前言 前面进行了多机器人编队仿真包括集中式和分布式&#xff0c;最近打算在实物机器人上跑一跑之前的编队算法。但由于Epuck2机器人长时间没使用&#xff0c;故对其进行固件的更新&#xff0c;…