28. 找出字符串中第一个匹配项的下标(力扣LeetCode)

文章目录

  • 28. 找出字符串中第一个匹配项的下标
    • 题目描述
    • 暴力
    • KMP算法

28. 找出字符串中第一个匹配项的下标

题目描述

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。

示例 1:

输入:haystack = “sadbutsad”, needle = “sad”
输出:0
解释:“sad” 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。

示例 2:

输入:haystack = “leetcode”, needle = “leeto”
输出:-1
解释:“leeto” 没有在 “leetcode” 中出现,所以返回 -1 。

提示:

  • 1 <= haystack.length, needle.length <= 104
  • haystack 和 needle 仅由小写英文字符组成

暴力

// 定义Solution类
class Solution {
public:// strStr函数接受两个字符串参数:haystack(主字符串)和needle(子串)int strStr(string haystack, string needle) {// 初始化count变量来跟踪匹配的连续字符数int count=0;// 初始化k变量来跟踪needle字符串中的当前位置int k=0;// 遍历haystack字符串for(int i=0; i<haystack.size(); i++){// 如果当前字符匹配,增加count并移动到needle的下一个字符if(haystack[i] == needle[k]){count++;k++;// 打印出当前的匹配长度(主要用于调试)cout << count << endl;// 如果全部字符都匹配,返回第一个匹配字符的下标if(count == needle.size())return i - count + 1;}// 如果当前字符不匹配else{// 重置i为上一个匹配序列的开始的下一个位置i = i - count;// 重置count和k为0,重新开始匹配count = 0;k = 0;}}// 如果遍历了整个haystack都没有找到完全匹配的needle,返回-1return -1;}
};

重要的代码段解释:

  • int i=0; i<haystack.size(); i++: 这个循环遍历主字符串haystack。
  • if(haystack[i] == needle[k]): 检查当前haystack的字符是否与needle的当前字符匹配。
  • count++; k++;: 如果匹配,增加count(匹配的字符数)并且k增加,使得下一次循环检查needle的下一个字符。
  • if(count == needle.size()): 如果count等于needle的长度,说明已经找到一个完全的匹配,返回第一个匹配的下标。
  • else分支: 当一个不匹配发生时,代码会重置i到当前检查序列的开始的下一个字符,并重置count和k为0,意味着重新开始匹配。
    需要注意的是,这段代码的性能并不是最优的,因为在发现一个字符不匹配时,它会回溯到上一个匹配序列的开始后面一个字符重新开始匹配,可能会导致多次重复检查同一个字符。更高效的字符串匹配算法如KMP算法能够在不回溯主字符串的情况下继续匹配。

KMP算法

不懂KMP算法的看这篇文章:28. 实现 strStr()

构造next数组图解
在这里插入图片描述

// 定义解决方案类
class Solution {
public:// strStr成员函数,接受两个字符串:haystack(搜索范围)和needle(目标字符串)int strStr(string haystack, string needle) {// 定义一个数组next用于存储KMP算法中的部分匹配表int next[needle.size()];// 计算needle的部分匹配表getnext(next, needle);//得到next数组// 定义一个指针j,用于指向needle的当前匹配位置//这里的i和j理解和下面getnext函数中类似//因为要回退的是j,所以j对应的是needle//所以i对应haystackint j=0;// 遍历haystack字符串for(int i=0; i<haystack.size(); i++) {// 使用while循环处理不匹配的情况// 如果j大于0且当前字符不匹配,则回退j到部分匹配的位置while(j > 0 && haystack[i] != needle[j]) {j=next[j-1];}// 如果当前字符匹配,则指针j递增if(haystack[i] == needle[j]) {j++;}// 如果j的值等于needle的长度,则表明找到了完整匹配// 返回匹配的起始下标if(j == needle.size()) {return i - needle.size() + 1;}}// 如果没有找到匹配,返回-1return -1;}private:// getnext函数用于计算KMP算法中的部分匹配表void getnext(int *next, const string& s) {// 初始化j为0,j指向前缀的末尾位置int j=0;// next数组的第一个元素总是0next[0]=0;//0的位置也是回退到0// 使用for循环计算next数组的其余部分for(int i=1; i<s.size(); i++) {//要比较前后缀是否相等,i从1开始,且i最后指向后缀末尾位置(s.size()-1)// 如果前后缀不相同,回退j的位置while(j > 0 && s[i] != s[j]) {j=next[j-1];//j进行回退}// 如果前后缀相同,j递增if(s[i] == s[j]) {j++;}// 更新next数组//更新分两种情况://第一种:相等时就更新//第二种:不相等时,j回退到0时更新为0next[i] = j;}}
};

这段代码中的KMP算法包含两个主要部分:

  1. getnext()函数计算部分匹配表(也就是next数组)。部分匹配表是KMP算法的核心,它记录了模式字符串needle中的前后缀的最长公共元素的长度。在搜索过程中不匹配时,可以利用这个信息跳过一些不必要的比较。

  2. strStr()函数使用部分匹配表来加速搜索过程。当出现不匹配的情况时,不用像暴力搜索那样从头开始比较,而是根据next数组回退到某一位置继续比较。

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

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

相关文章

如何实现双向循环链表

博主主页&#xff1a;17_Kevin-CSDN博客 收录专栏&#xff1a;《数据结构》 引言 双向带头循环链表是一种常见的数据结构&#xff0c;它具有双向遍历的特性&#xff0c;并且在表头和表尾之间形成一个循环。本文将深入探讨双向带头循环链表的结构、操作和应用场景&#xff0c;帮…

论文阅读:Ground-Fusion: A Low-cost Ground SLAM System Robust to Corner Cases

前言 最近看到一篇ICRA2024上的新文章&#xff0c;是关于多传感器融合SLAM的&#xff0c;好像使用了最近几年文章中较火的轮式里程计。感觉这篇文章成果不错&#xff0c;代码和数据集都是开源的&#xff0c;今天仔细读并且翻译一下&#xff0c;理解创新点、感悟研究方向、指导…

【MQ05】异常消息处理

异常消息处理 上节课我们已经学习到了消息的持久化和确认相关的内容。但是&#xff0c;光有这些还不行&#xff0c;如果我们的消费者出现问题了&#xff0c;无法确认&#xff0c;或者直接报错产生异常了&#xff0c;这些消息要怎么处理呢&#xff1f;直接丢弃&#xff1f;这就是…

【Leetcode每日一题】二分查找 - 寻找旋转排序数组中的最小值(难度⭐⭐)(22)

1. 题目解析 Leetcode链接&#xff1a;153. 寻找旋转排序数组中的最小值 这个题目乍一看很长很复杂&#xff0c;又是旋转数组又是最小值的 但是仔细想想&#xff0c;结合题目给的示例&#xff0c;不难看出可以用二分的方法来解决 核心在于找到给定数组里面的最小值 2. 算法原…

androidstudio小游戏,可能是全网最细的Android-资源加载机制剖析

80%的人答不出的字节跳动面试问题—Framework 视频内容概要&#xff1a; 1.framework层整体执行流程分析 2.XML文件加载源码分析 3.自定义VIEW源码分析 4.切入源码执行流程实现屏幕适配 源码分析的角度分析——HashMap原理讲解 1&#xff09;HashMap的内部结构 2&#xff09;…

微服务架构 SpringCloud

单体应用架构 将项目所有模块(功能)打成jar或者war&#xff0c;然后部署一个进程--医院挂号系统&#xff1b; > 优点: > 1:部署简单:由于是完整的结构体&#xff0c;可以直接部署在一个服务器上即可。 > 2:技术单一:项目不需要复杂的技术栈&#xff0c;往往一套熟悉的…

ubuntu常见配置

ubuntu各个版本的安装过程大差小不差&#xff0c;可以参考&#xff0c;ubuntu20.04 其它版本换一下镜像版本即可 安装之后需要配置基本的环境&#xff0c;我的话大概就以下内容&#xff0c;后续可能有所删改 sudo apt-get update sudo apt-get install gcc sudo apt-get inst…

市场复盘总结 20240228

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 二进三&#xff1a; 进级率 25% 最常用的二…

Docker部署Portainer图形化管理工具

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 Portainer 是一个轻量级的容器管理工具&#xff0c;可以通过 Web 界面对 Docker 容器进行管理和监控。它提供了可…

动态规划之使用最小花费爬楼梯【LeetCode】

动态规划之使用最小花费爬楼梯 LCR 088. 使用最小花费爬楼梯解法1解法2 LCR 088. 使用最小花费爬楼梯 LCR 088. 使用最小花费爬楼梯 解法1 状态表示&#xff08;这是最重要的&#xff09;&#xff1a;dp[i]表示以第i级台阶为楼层顶部&#xff0c;到达第i层台阶的最低花费。 状…

STM32定时器原理和使用

简介 STM32微控制器提供了一系列的定时器模块&#xff08;TIM&#xff09;&#xff0c;不同型号的STM32有不同数目和类型的定时器。常见的有&#xff1a; 基本定时器&#xff08;TIM6, TIM7等&#xff09;: 主要用于定时和触发一些基础事件&#xff0c;如ADC转换启动。只具有…

《隐私计算简易速速上手小册》第8章:隐私计算对机器学习和 AI 的影响(2024 最新版)

文章目录 8.1 机器学习中的隐私问题8.1.1 基础知识8.1.2 主要案例:使用差分隐私的机器学习8.1.3 拓展案例 1:基于隐私的数据聚合8.1.4 拓展案例 2:保护隐私的推荐系统8.2 使用隐私计算加强 AI 安全8.2.1 基础知识8.2.2 主要案例:使用同态加密的数据分析8.2.3 拓展案例 1:安…