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

news2025/1/23 15:46:55

文章目录

  • 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,返回-1
        return -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对应haystack
        int 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;
            }
        }

        // 如果没有找到匹配,返回-1
        return -1;
    }

private:
    // getnext函数用于计算KMP算法中的部分匹配表
    void getnext(int *next, const string& s) {
        // 初始化j为0,j指向前缀的末尾位置
        int j=0;
        // next数组的第一个元素总是0
        next[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时更新为0
            next[i] = j;
        }
    }
};

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

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

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

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

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

相关文章

【PHP】Workerman开源应用容器的GatewayWorker 与 iOS-OC对接

Workerman 开源高性能PHP应用容器 workerman是一款开源高性能PHP应用容器,它大大突破了传统PHP应用范围,被广泛的用于互联网、即时通讯、APP开发、硬件通讯、智能家居、物联网等领域的开发。 PHPSocket.io PHP版本的socket.io,具有良好的客户端兼容性,常用于即时通讯领域…

在CentOS上使用Docker搭建Halo博客并实现远程访问的详细指南

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. Docker部署Halo1.1 检查Docker版本1.2 在Docker中部署Halo 二. Linux安装Cpol…

亚信安慧AntDB数据库与流式处理的有机融合

流式处理的概念 2001年9月11日&#xff0c;美国世贸大楼被袭击&#xff0c;美国国防部第一次将“主动预警”纳入国防的宏观战略规划。而IBM作为当时全球最大的IT公司&#xff0c;承担了大量基础支撑软件研发的任务。其中2009年正式发布的IBM InfoSphere Streams&#xff0c;就是…

文献阅读:秀丽隐杆线虫的神经肽能连接组

文献介绍 「文献题目」 The neuropeptidergic connectome of C. elegans 「研究团队」 William Schafer&#xff08;MRC分子生物学实验室&#xff09; 「发表时间」 2023-11-15 「发表期刊」 Neuron 「影响因子」 16.2 「DOI」 10.1016/j.neuron.2023.09.043 摘要 人们正在…

华为数通方向HCIP-DataCom H12-821题库(单选题:481-500)

第481题 以下关于基于SD-WAN思想的EVPN互联方案的描述,错误的是哪一项? A、通过部署独立的控制面,将网络转发和控制进行了分离,从而实现了网络控制的集中化 B、通过对WAN网络抽象和建模,将上层网络业务和底层网络具体实现架构进行解耦,从而实现网络自动化 C、通过集中的…

GPM 是什么?

G、P、M是Go调度器的三个核心组件&#xff0c;各司其职。在它们精密地配合下&#xff0c;Go调度器得以高效运转&#xff0c;这也是Go天然支持高并发的内在动力。今天这篇文章我们来深入理解GPM模型。 先看G&#xff0c;取goroutine的首字母&#xff0c;主要保存goroutine的一些…

团结引擎——DotNet Wasm方案

参考&#xff1a;团结引擎 DotNet WebAssembly(Wasm) 介绍 一、当前编译流程 通过IL2CPP将C#转成C/C&#xff1b;通过Emscripen将C/C转成WebAssembly&#xff1b; 二、 当前存在问题 IL2CPP在处理类似泛型、反射结构时&#xff0c;由于缺少运行时信息&#xff0c;必须全量生…

备战蓝桥杯Day18 - 双链表

一、每日一题 蓝桥杯真题之工作时长 这个题写代码做的话很麻烦&#xff0c;而且我也不一定能写出来&#xff0c;所以我直接就是用的excel来计算的时间和。 使用excel的做法 1.先把文件中的时间复制到excel中。 2.把日期和时间分到两列。 分成两列的步骤&#xff1a; 选中要…

让两个电脑通信的方法(TCP连接,UDP连接,C/S架构)

目录 TCP-面向连接UDP-面向无连接C/S架构服务器和客户端的工作过程C/S架构例子 让两个电脑通信的方法是 在C/S的基础上&#xff0c;采用TCP和UDP的方式连接 TCP-面向连接 UDP-面向无连接 C/S架构 服务器和客户端的工作过程 C/S架构例子 服务器与客户端通信的过程类似公司与客户…

【Git教程】(五)分支 —— 并行式开发,分支相关操作(创建、切换、删除)~

Git教程 分支 1️⃣ 并行式开发2️⃣ 修复旧版本中的 bug3️⃣ 分支4️⃣ 当前活跃分支5️⃣ 重置分支指针6️⃣ 删除分支7️⃣ 清理提交对象&#x1f33e; 总结 对于版本提交为什么不能依次进行&#xff0c;以便形成一条直线型的提交历史记录&#xff0c;我们认为有 以下两个…

在PyCharm中使用Git

安装Git CMD检查Git版本 打开cmd&#xff0c;输入git version&#xff0c;检查当前下载版本 配置git的user信息 在cmd中输入 git config --global user.name "用户名"git config --global user.email "用户邮箱"输入&#xff1a;git config --list&…

自然语言处理: 第十三章Xinference部署

项目地址: Xorbitsai/inference 理论基础 正如同Xorbits Inference&#xff08;Xinference&#xff09;官网介绍是一个性能强大且功能全面的分布式推理框架。可用于大语言模型&#xff08;LLM&#xff09;&#xff0c;语音识别模型&#xff0c;多模态模型等各种模型的推理。通…

安装极狐GitLab Runner并测试使用

本文继【新版极狐安装配置详细版】之后继续 1. 添加官方极狐GitLab 仓库&#xff1a; 对于 RHEL/CentOS/Fedora&#xff1a; curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash2. 安装最新版本的极狐G…

node.js 用 xml2js.Parser 读 Freeplane.mm文件,生成测试用例.csv文件

Freeplane 是一款基于 Java 的开源软件&#xff0c;继承 Freemind 的思维导图工具软件&#xff0c;它扩展了知识管理功能&#xff0c;在 Freemind 上增加了一些额外的功能&#xff0c;比如数学公式、节点属性面板等。 编写 mm_xml2js_csv.js 如下 // 用 xml2js.Parser 读 F…

设计模式-代理模式(静态代理,动态代理)

定义 代理模式Proxy是⼀种结构型设计模式&#xff0c;能够增强一些功能&#xff0c;不会影响到之前核心功能的流程。 结构图 1 通过实现接口的方式 2 通过继承类的方式 代理模式与装饰器模式 IT老齐白话设计模式 装饰和代理有着相似的结构&#xff0c; 但是其意图却⾮常…

腾讯云4核8G服务器优惠价格表(轻量+CVM)

腾讯云4核8G服务器多少钱&#xff1f;轻量应用服务器4核8G12M带宽一年446元、646元15个月&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;标准型SA2服务器1444.8元一年&#xff0c;在txy.wiki可以查询详细配置和精准报价…

DAY12_VUE基本用法详细版

目录 0 HBuilderX酷黑主题修改注释颜色1 VUE1.1 VUE介绍1.2 Vue优点1.3 VUE入门案例1.3.1 导入JS文件1.3.2 VUE入门案例 1.4 VUE基本用法1.4.1 v-cloak属性1.4.2 v-text指令1.4.3 v-html指令1.4.4 v-pre指令1.4.5 v-once指令1.4.6 v-model指令1.4.7 MVVM思想 1.5 事件绑定1.5.1…

C# OpenCvSharp DNN Yolov8-OBB 旋转目标检测

目录 效果 模型信息 项目 代码 下载 C# OpenCvSharp DNN Yolov8-OBB 旋转目标检测 效果 模型信息 Model Properties ------------------------- date&#xff1a;2024-02-26T08:38:44.171849 description&#xff1a;Ultralytics YOLOv8s-obb model trained on runs/DOT…

【.Net 使用阿里云OSS 存储文件】

一、使用NuGet安装【Aliyun.OSS.SDK】 注意&#xff1a;如果有多个项目&#xff0c;需要在具体使用的项目跟启动项目都安装同一版本的Aliyun.OSS.SDK 二、上传代码 using Aliyun.OSS; using System.IO; using System; using CadApplication.Service.Dto; using System.Net; us…

Excel 使用空格或TAB分列

1 选择“数据”>“分列”。 在“文本分列向导”中&#xff0c;选择“分隔符号”>“下一步”。 选择数据的“分隔符”。 例如&#xff0c;“逗号”和“空格”。 可在“数据预览”窗口预览数据。 选择“下一步”&#xff0c;在工作表 目标&#xff0c;在工作表中想显示拆分…