力扣28. 找出字符串中第一个匹配项的下标(暴力手撕+KMP算法)

LeetCode题解:28.找出字符串中第一个匹配项的下标【Python题解超详细,滑动窗口法、内置 find 函数、KMP算法】,知识拓展, KMP算法 LeetCode题解:28.找出字符串中第一个匹配项的下标【Python题解超详细,滑动窗口法、内置 find 函数、KMP算法】,知识拓展, KMP算法,基本概况、主要特点、核心思想、匹配过程、实现代码 28.找出字符串中第一个匹配项的下标:给你两个字符串haystack和needle,请你在haystack字符串中找出needle字符串的第一个匹配项的下标(下标从 0 开始)。如果needle不是haystack的一部分,则返回-1。 阅读详情

找出字符串中第一个匹配项的下标:Java解法详解

来源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 仅由小写英文字符组成

 详解

一、暴力手撕法(双指针法)

思路

采用双指针法进行匹配:

  • 初始化指针p(主串)和q(子串),从头开始逐个字符比对
  • 若当前字符不匹配,则p回溯到主串下一位置,q重置到子串起始位置
  • 重复上述过程,直至q遍历完整个子串
  • 此时p-q的差值即为子串首次出现的位置索引

 完整代码

class Solution {
    public int strStr(String haystack, String needle) {
        if (needle.isEmpty()) {
            return 0;
        }
        int p = 0; // 索引 p 用于 haystack
        int q = 0; // 索引 q 用于 needle

        while (p < haystack.length() && q < needle.length()) {
            if (haystack.charAt(p) == needle.charAt(q)) {
                p++;
                q++;
            } else {
                p = p - q + 1; // 重置 p 和 q
                q = 0;
            }

            // 如果 needle 全部匹配,返回起始位置
            if (q == needle.length()) {
                return p - q;
            }
        }
        return -1; // 未找到匹配
    }
}

缺点

重复匹配失败会导致从头开始重新尝试,不仅效率低下且浪费资源。

二、KMP算法(最通俗易懂版)

当 haystack = "abcabefg" 且 needle = "abefg" 时,采用双指针匹配方法。在匹配过程中,当遇到主串中的字符'c'与模式串不匹配时,算法会触发回溯机制。

abcabefg
abefg

匹配失败后重新从起始位置开始尝试:

haystackabcabefg
needleabefg

为什么不直接从匹配失效后面再接着重新找呢?这样不就快一些吗?

haystackabcabefg
needleabefg

原因:直接从匹配失效的后面接着找可能会导致遗漏某些潜在的匹配位置。因为模式串内部可能存在重复的子串,回溯到部分匹配的位置可以确保我们不会错过这些子串可能带来的匹配机会。

好,接下来再看一个例子

haystack = "abababcaa" 且 needle = "ababc"

haystackabababcaa
needleababc

当匹配最后一个元素不成功时,若直接从匹配失效后再接着找那就出错了,因为实质上要从一下地方再进行匹配

haystackabababcaa
needleababc

如何确定匹配的起始位置?当匹配失败时,如何精准定位需要回溯的位置?

当两个字符串在匹配过程中出现错误时,若它们之前存在相同的前缀(如"ab"),我们可以通过定义一个数组来记录每个位置匹配失败时,其前缀是否与其他元素相匹配。

代码解析

    private int[] computeLPSArray(String needle) {
        int length = 0; // 当前相同前缀后缀的长度
        int i = 1; // 从第二个字符开始计算 LPS
        int[] lps = new int[needle.length()]; // 初始化 LPS 数组
        lps[0] = 0; // 第一个字符的 LPS 值为 0

        while (i < needle.length()) { // 遍历 needle
            if (needle.charAt(i) == needle.charAt(length)) { // 如果字符匹配
                length++; // 增加相同前缀后缀的长度
                lps[i] = length; // 记录 LPS 值
                i++; // 移动 i
            } else { // 如果字符不匹配
                if (length != 0) {
                    length = lps[length - 1]; // 回退 length
                } else {
                    lps[i] = 0; // 如果 length 为 0,记录 LPS 值
                    i++; // 移动 i
                }
            }
        }

        return lps; // 返回 LPS 数组
    }

这个方法就可以得到一个数组,数组元素表示当前元素存在的最大前缀

例如,对于模式串 needle = "ababc",部分匹配表如下:

字符ababc
前缀函数值00120
  • 对于第一个字符 a,没有前缀和后缀,所以值为0。
  • 对于第二个字符 b,没有相同前后缀,所以值为0。
  • 对于第三个字符 a,与第一个字符相同,所以值为1。
  • 对于第四个字符 b,与第二个字符相同,所以值为2。
  • 对于第五个字符 c,没有相同前后缀,所以值为0。
  1. 匹配过程:
    在匹配过程中,当发生不匹配时,我们根据部分匹配表中的值来决定回溯的位置。

    例如,对于 haystack = "abababcaa" 和 needle = "ababc":

    haystackabababcaa
    needleababc
    • 当匹配到第四个字符 b 时,发生不匹配。
    • 根据部分匹配表,我们知道在位置3(从0开始计数)的值为2,这意味着在模式串的前缀 abab 中,最长相同前后缀的长度为2。
    • 所以,我们可以将模式串回溯到位置2(即第二个 a 的位置)重新开始匹配。
  2. 回溯位置的确定:

    • 当匹配失败时,我们查看部分匹配表中当前位置的值,这个值就是我们需要回溯到的位置。
    • 在上述例子中,匹配失败时,我们根据部分匹配表的值2,将模式串回溯到第二个 a 的位置。

借助该数组,我们能够快速确定匹配失效时需要回溯的位置。完整代码及具体解析如下:

class Solution {
    public int strStr(String haystack, String needle) {
        if (needle.isEmpty()) {
            return 0; // 如果 needle 为空,直接返回 0
        }

        int[] lps = computeLPSArray(needle); // 计算 needle 的 LPS 数组
        int i = 0; // 索引 i 用于遍历 haystack
        int j = 0; // 索引 j 用于遍历 needle

        while (i < haystack.length()) { // 遍历 haystack
            if (haystack.charAt(i) == needle.charAt(j)) { // 如果字符匹配
                i++; // 移动 i
                j++; // 移动 j
            }

            if (j == needle.length()) { // 如果 needle 全部匹配
                return i - j; // 返回匹配的起始位置
            } else if (i < haystack.length() && haystack.charAt(i) != needle.charAt(j)) { // 如果字符不匹配
                if (j != 0) {
                    j = lps[j - 1]; // 根据 LPS 数组回退 j
                } else {
                    i++; // 如果 j 为 0,直接移动 i
                }
            }
        }

        return -1; // 未找到匹配
    }

    private int[] computeLPSArray(String needle) {
        int length = 0; // 当前相同前缀后缀的长度
        int i = 1; // 从第二个字符开始计算 LPS
        int[] lps = new int[needle.length()]; // 初始化 LPS 数组
        lps[0] = 0; // 第一个字符的 LPS 值为 0

        while (i < needle.length()) { // 遍历 needle
            if (needle.charAt(i) == needle.charAt(length)) { // 如果字符匹配
                length++; // 增加相同前缀后缀的长度
                lps[i] = length; // 记录 LPS 值
                i++; // 移动 i
            } else { // 如果字符不匹配
                if (length != 0) {
                    length = lps[length - 1]; // 回退 length
                } else {
                    lps[i] = 0; // 如果 length 为 0,记录 LPS 值
                    i++; // 移动 i
                }
            }
        }

        return lps; // 返回 LPS 数组
    }
}

 既然你看到这里了,那么恭喜你,KMP算法你已经会写了!

RK3568平台YOLO11模型部署实战:从环境搭建、模型转换到板端性能优化全解析 摘要: 本文详细介绍了在RK3568平台上从零部署YOLO11模型的完整流程。主要内容包括:1) 基于Conda搭建Python 3.8开发环境并安装RKNN-Toolkit2工具链;2) 使用LabelImg工具标注数据并构建YOLO格式数据集;3) 基于Ultralytics框架进行YOLO11模型训练及参数优化;4) 实现PyTorch→ONNX→RKNN的完整模型转换链。文章特别针对RK3568平台的NPU特性提供了关键参数配置建议,并分享了实际开发中的经验总结,最终可达到30FPS的稳定推理性能。 阅读详情

相关推荐

【项目实战-MATLAB】:基于机器学习的虹膜识别系统设计

虹膜识别主要包括虹膜定位、虹膜裁剪、极坐标变换、归一化、HOG特征提取、虹膜识别六个主要步骤。本系统采用MATLAB作为开发工具实现 主要算法:霍夫变换预处理 HOG特征提取 SVM进行识别

qq_45047246的博客 6537

【LeetCode算法】28. 找出字符串中第一个匹配项的下标

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

熊熊饲养员的优快云! 725

TTL电路搭建半加器实验:操作指南完整版

通过TTL电路搭建半加器,详解逻辑设计与实验步骤,帮助掌握数字电路中的半加器工作原理与实际应用,适合电子技术初学者动手实践。

weixin_42524864的博客 355

kmp算法pmt数组构建的理解

我们找到这样一个更短的火车头,看看在更短的火车头后面加车厢,是否能够增长火车头的长度,如果不行,那就再找一个更更短的,这样一直循环,直到找到一个符合条件的公共前后缀,或者没找到,那pmt[i]就为0(公共前后缀的长度为零)。再回过头来看这句代码:length = lps[length - 1],length是当前公共前后缀的长度,lps[length-1]是前length-1个字符的公共前后缀的长度,也就是前缀的前缀的长度。前缀=后缀,前缀的前缀=前缀的后缀,后缀的前缀=后缀的后缀,

J951357j的博客 377

calibration的“前世今生”——从simulink开发到CANape的XCP标定

整体思路 备注: elf可简单的看作为hex和map的集合,其中包括可执行的程序、变量及其对应的地址(simulink生成代码是也可以勾选生成ASAP2的a2l文件,有变量但变量对应的地址为空,只有编译后才分配地址) 定义变量是观测值还是标定值需要在simulink中的数据字典定义变量存储类型,详见simulink系列。 1. 前期准备A2L的制作 安装完成CanApe软件 , 插上CanApe硬件( 如:vector 1640A)。打开A2L编辑软件 ASAP2 Editor(注意不是ASAP2 Vi

IHTY_NUI的博客 1万+

基于 Qt C++ 的战术通信终端

logMessage(QString("新客户端连接来自: %1:%2").arg(incomingTcpSocket->peerAddress().toString()).arg(incomingTcpSocket->peerPort()));logMessage(QString("服务器已启动,在 [%1]:%2 监听IPv6连接...").arg(ui->lineEditAddress->text()).arg(port));

寒寒豆豆软件公司的博客 77

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

​暴力匹配法:直接但有效,适用于简单场景。​优化点:通过首字符匹配筛选,减少不必要的比较。​边界处理:明确处理长度不足的情况,避免越界。​适用性:适合题目给定的小规模输入(题目约束长度 ≤10^4)。若数据量极大,需使用KMP等高效算法。

m0_49844997的博客 281

光通量与辐射通量之间的换算

由理论和实验可知存在两种定义: 1W1W1W(瓦特)的频率为540×1012Hz540\times10^{12}Hz540×1012Hz(赫兹)的单色辐射的辐射通量等于683lm(流明)683lm(流明)683lm(流明).。 1lm1lm1lm的频率为540×1012Hz540\times10^{12}Hz540×1012Hz的单色通量等于1683=0.001464W\frac{1}{683}=0.001464W6831​=0.001464W。 从上述定义中我们可以得到什么呢?我们知道光速: c=3×

u011699626的博客 3270

(第13、14天)【leetcode题解】#右旋字符串 28、找出字符串中第一个匹配项的下标

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。这都需要使用指针(下标),双指针是常用的,它可以帮助原地修改字符串,还可以降低时间复杂度。匹配时只遍历一次文本串,每遍历到一个字符只做一次判断和常数级的操作。1.字符串的操作和数组有共性:需要下标访问、各种操作都是基于使用下标进行的元素修改。最多遍历全部的本文串,并在每次遍历文本串的内部遍历模式串。翻转操作需要遍历数量级为n的次数。:反转顺序发生改变。

m0_73755059的博客 2119

QGis二次开发 —— 5.1、基于qgis开发雷达扫描、无人机飞行跟踪等(附:源码及工程)

基于qgis开发雷达扫描、无人机飞行跟踪等

323

新手强化学习—深入解析 YOLOv13 项目包中的文件结构和各文件作用

YOLOv13是YOLO系列最新发布的计算机视觉模型。在这篇博客中,我将深入分析YOLOv13中各个文件的作用,对整个项目的文件结构有更清晰的认识。

Limiiiing的博客 482

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

因为前缀部分(如abc)和后缀部分(如abc)完全相同,而前缀部分(如abc)和中间部分(如d)不相同,因此前缀部分(如abc)和中间部分对齐(如d)时,必然匹配失败。本题如果采用暴力解法的话,可以定义两个指针 i,j,其中 i 指针用于扫描 S(haystack)串,j 指针用于扫描 T(needle)串。注意,判断前缀和后缀是否相同,都是从左往右逐一比对,因此上面例子中,长度为3的前缀"aab"和后缀"baa"是不相同的。"leeto" 没有在 "leetcode" 中出现,所以返回 -1。

优快云 1356

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Golang leetcode28 找出字符串中第一个匹配项的下标 KMP算法详解

因此我们可以对模式字符串建立一个数组,分别记录当第几个开始不对应时,下次从第几个再开始比较,也就是常说的。前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。第4个字母不一致,但前三个字母是一致的,那么当我们继续寻找时,没有必要再从第一个字母开始对应。那么,从这里我们又能够发现,下次从第几个数字开始进行比较,只跟这次重复的子串有关系,,也就是以字符串第一个字符作为开头,同时不包括最后一个字符的所有子串,续接我们提到的前后缀的概念,前三个字符为aba,则前缀为。

kingsill的博客 1362

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【字符串匹配】【KMP算法】Leetcode 28 找出字符串中第一个匹配项的下标☆

【字符串匹配】【KMP算法】Leetcode 28 找出字符串中第一个匹配项的下标☆

prince0520的博客 1554

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

力扣经典150题第二十三题:找出字符串中第一个匹配项的下标

在字符串处理中,查找第一个匹配项的下标是一个常见且基础的问题。这个问题在算法面试和日常编程中经常遇到。本文将介绍如何解决这一问题并给出相应的代码实现。通过实现字符串匹配算法,我们可以有效地找出字符串中第一个匹配项的下标。在实际应用中,字符串匹配是一个常见且重要的问题。这里我们使用了简单的暴力匹配算法,对目标字符串的每个可能起始位置进行了遍历匹配,找到第一个匹配项的下标。

私聊前往站内信:https://i.youkuaiyun.com/#/msg/chat/weixin_44976692 1万+

力扣刷题笔记:找出字符串中第一个匹配项的下标(LeetCode28)—— Java

暴力解法虽然直观,但在大规模数据下效率较低。我会在后面的文章中介绍更高效的KMP算法,通过预处理模式串优化匹配过程,敬请期待!主包有点太啰嗦了,请原谅我哈哈。

2501_90563889的博客 980

27-算法打卡-字符串-找出字符串中第一个匹配项的下标-leetcode(28)-第二十七天

28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)28. 找出字符串中第一个匹配项的下标 - 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1。示例 1:输入:haystack = "sadbutsad", needle = "sad"输出:0解释:"sad" 在下标 0 和 6 处匹配。

Bonnie_1215的博客 1574

算法leetcode|28. 找出字符串中第一个匹配项的下标(rust重拳出击)

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

二当家的白帽子 3353

力扣刷题笔记:找出字符串中第一个匹配项的下标(LeetCode28)—— KMP 算法版

前缀表是针对needle(模式串)的,数组名叫nextnext[i]表示这个子串中,最长的相等前缀和后缀的长度。这里得先搞懂两个词:前缀:从开头开始的子串(不包含最后一个字符),比如 "ABC" 的前缀是 "A"、"AB"后缀:从结尾往前的子串(不包含第一个字符),比如 "ABC" 的后缀是 "C"、"BC"next[0]:子串 "A",没有前缀和后缀,所以 0next[1]:子串 "AB",前缀 "A" 和后缀 "B" 不相等,所以 0next[2]

2501_90563889的博客 1027

LeetCode:28. 找出字符串中第一个匹配项的下标 ——【1、理解 KMP 算法】

LeetCode:28. 找出字符串中第一个匹配项的下标 ——【1、理解 KMP 算法】 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。

Super algorithm 的博客,技术爱好者。 807

代码随想录算法训练营第九天|LeetCode151.翻转字符串中的单词、KamaCoder55. 右旋字符串、LeetCode28.找出字符串中第一个匹配项的下标、LeetCode459.重复的子串

LeetCode151.翻转字符串中的单词文章链接:代码随想录视频链接:LeetCode:151.翻转字符串里的单词KamaCoder55. 右旋字符串文章链接:代码随想录LeetCode28.找出字符串中第一个匹配项的下标文章链接:代码随想录算法视频链接:KMP算法(理论篇)算法视频链接:求next数组(代码篇)LeetCode459.重复的子字符串文章链接:代码随想录视频链接:LeetCode:459.重复的子字符串最长前后缀匹配字符串就是一个字符串s的头部一部分子串和尾部一部分子串完全相同且。

python1_1的博客 1343

力扣热题100实战 | 第28期:找出字符串中第一个匹配项的下标——从暴力到KMP的跃迁

本文是力扣热题100实战系列的第二十八篇,深度解析找出字符串中第一个匹配项的下标这道经典字符串题。作为LeetCode第28题,它是一道简单但核心的面试题,也是字符串匹配算法的最佳入门案例。题目要求在主串中找出子串第一次出现的位置。本文从最直观的暴力匹配法O(n×m)讲起,分析其重复匹配的弊端,然后逐步引出KMP算法的核心思想,通过构建next数组利用已匹配信息,将时间复杂度优化到O(n+m)。通过图解和详细代码注释,帮助读者理解KMP的前缀后缀概念、next数组的构建过程,以及匹配时的指针移动策略。无论你

LinuxSRE、k8s、运维、DBA、大数据 879

LeetCode面试150——28找出字符串中第一个匹配项的下标

LeetCode面试150——28找出字符串中第一个匹配项的下标题目讲解和代码实现

Junmo12345的博客 1156

【LeetCode刷题记录】简单篇-28-找出字符串中第一个匹配项的下标

给你两个字符串haystack和needle,请你在haystack字符串中找出needle字符串的第一个匹配项的下标(下标从 0 开始)。如果needle不是haystack的一部分,则返回-1。 这道题是经典的字符串匹配问题:即在主串寻找子串,如果存在子串则返回子串在主串中的起始位置,如果不存在则直接返回-1。给出两种解法。

呜呼哈嘿嚯的博客 1520

代码随想录算法训练营第9天 | LeetCode28.找出字符串中第一个匹配项的下标、LeetCode459.重复的子字符串

否则根本就不存在子串的往复,因为根本没有相等的前后缀。

m0_68237332的博客 1313

leetcode28.找出字符串中第一个匹配项的下标,KMP算法保姆级教程(带动图)

本文详细解析了“查找字符串首个匹配项下标”问题的多种解法,包括调用API、暴力求解和KMP算法。调用API如`indexOf`方法可一行代码实现,简单高效但可能缺乏面试深度。暴力求解通过逐字符对比完成匹配,时间复杂度为O(m*n),适合理解基础逻辑。KMP算法利用最长相同前后缀信息优化匹配过程,显著提高效率,适用于大规模字符串处理场景,时间复杂度为O(m+n)。文章结合案例深入讲解了KMP算法中前缀表的构建与应用,帮助读者全面掌握字符串匹配的核心技巧。

我只管埋头前行,剩下的交给时间。 1333
上一篇: 力扣389.找不同
下一篇: 力扣242. 有效的字母异位词
AffectionGF
博客等级 码龄3年 78粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值