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

1. 题目

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

题目描述

给你两个字符串 haystack 和 needle ,在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1。

示例

输入:haystack = "sadbutsad", needle = "sad"

输出:0

输入:haystack = "leetcode", needle = "leeto"

输出:-1

约束

  • (1 <= haystack.length, needle.length <= 10^4)

  • haystack 和 needle 仅由小写英文字符组成

2. 最佳解题思路描述(暴力双指针朴素匹配,适合入门)

  1. 遍历主串每个下标 i,当 haystack[i] == needle[0] 时,开启子串匹配;

  2. 从 i 开始连续比对 len(needle) 个字符:

    • 全部匹配成功:直接返回起始下标 i;

    • 中途字符不相等:匹配失败,重置标记继续外层循环;

  3. 遍历结束无匹配返回 -1。

优势

逻辑直白,容易手写;无需复杂 KMP 预处理;适合题目数据范围。

时间复杂度最坏 (O(n*m)),空间 (O(1))。

3. 我的可优化代码(逻辑大体正确,存在边界 bug 与冗余变量)

复制代码
class Solution {
public:
    int strStr(string haystack, string needle) {
        int len = needle.size();
        int num = 0;
        int index = -1;
        int flag = 0;
        for(int i = 0;i<haystack.size();i++){
            if(haystack[i]==needle[0]){
                index = i;
                for(int j = i;j<i+len;j++){
                    if(haystack[j] == needle[j-i]){
​
                    }
                    else{
                        index = -1;
                        break;
                    }
                }
            }
            if(index!=-1){
                break;
            }
        }
        return index;
    }
};

代码问题说明

  1. 数组越界风险(致命 bug)

    内层循环 j < i + len 没有限制 j < haystack.size()。

    若主串剩余字符不足 len 个,haystack[j] 访问越界,程序崩溃。

    例:haystack="abc", needle="bcd",i=1 时 i+len=4,j 取到 3 超出下标。

  2. 无效冗余变量

    num、flag 定义后全程未使用,无意义,可直接删除。

  3. 空循环体可读性差

    相等时无操作,仅不相等才处理,逻辑阅读困难。

  4. 循环范围可剪枝优化

    外层 i 最多只需走到 haystack.size() - len,超过该起点不可能完整容纳子串,减少无效循环。

4. 规范修正版代码(朴素暴力匹配,修复越界)

复制代码
class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size();
        int m = needle.size();
        // 剪枝:i最大到 n-m,再往后长度不够
        for (int i = 0; i <= n - m; ++i) {
            bool match = true;
            for (int j = 0; j < m; ++j) {
                if (haystack[i + j] != needle[j]) {
                    match = false;
                    break;
                }
            }
            if (match) {
                return i;
            }
        }
        return -1;
    }
};

5. 总结

  1. 原代码核心匹配逻辑思路没问题,但缺少长度边界判断,存在数组越界崩溃;

  2. 优化关键点:外层循环上限设为 n-m,从根源避免内层越界;

  3. 无需多余标记变量,用 bool 记录单次匹配状态更清晰;

  4. 找到匹配起点直接 return,不用额外保存 index 再 break。

6. 相关知识拓展

拓展 1:库函数极简写法(面试仅作了解)

复制代码
int strStr(string haystack, string needle) {
    size_t pos = haystack.find(needle);
    return pos == string::npos ? -1 : pos;
}

底层封装匹配逻辑,面试不建议作为主力解法。

拓展 2:KMP 算法(高效线性匹配,大数据最优)

预处理 needle 得到 next 前缀数组,匹配失败时主串指针不回退,时间 (O(n+m)):

复制代码
class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size(), m = needle.size();
        if(m == 0) return 0;
        vector<int> next(m,0);
        // 构建next数组
        for(int i=1,j=0;i<m;i++){
            while(j>0 && needle[i]!=needle[j]) j=next[j-1];
            if(needle[i]==needle[j]) j++;
            next[i]=j;
        }
        // 匹配
        for(int i=0,j=0;i<n;i++){
            while(j>0 && haystack[i]!=needle[j]) j=next[j-1];
            if(haystack[i]==needle[j]) j++;
            if(j==m) return i-m+1;
        }
        return -1;
    }
};

拓展 3:复杂度对比

  1. 朴素暴力(修正版):最坏 (O(n*m)),(O(1));

  2. KMP 算法:(O(n+m)),(O(m));

  3. string::find:底层优化实现,实际效率很高。

拓展 4:易错点复盘

  1. 忘记限制外层 i 上限,导致内层访问主串越界;

  2. 多余无用变量增加代码冗余;

  3. 内层循环判断只处理不相等分支,可读性差。

相关推荐
UIU1142 分钟前
递归算法与汉诺塔
c++·学习·算法·c#·递归
用户979984807185 小时前
200 行代码写一个能跑的 AI Agent:不依赖任何框架,只靠 tool-calling 原理
算法
threerocks5 小时前
【Muse实战】X 流量作战室搭建保姆级教程 - 拥有你自己的运营团队
算法
GreenTea5 小时前
深度拆解 ScienceBuddy:如何用“双层递归自进化”构建高可靠科研 Agent Harness
前端·后端·算法
花椒技术6 小时前
2.46 秒生成 5 秒视频:拆解 H3 Max 的模型、推理栈与硬件协同
算法·音视频开发·视频编码
vivo互联网技术6 小时前
ART:妆容迁移框架,重新定义高保真妆容迁移 | ECCV 2026
人工智能·算法·图像识别
用户0441440924496 小时前
卫星信号模拟器里的四个坐标转换公式
算法
橘和柠6 小时前
阿里 open-code-review (AI代码审查工具)实战:安装、四层规则链、自定义规则格式与实测避坑
算法·面试
得物技术6 小时前
别再只卷向量检索了,得物交易搜索如何用“生成式”实现召回范式跃迁?
人工智能·算法·llm
罗西的思考6 小时前
[Agent Memory / 强化学习] MemPO源码学习笔记 ---(4)--- Rollout实现细节
人工智能·算法