每日算法练习:LeetCode 28. 找出字符串中第一个匹配项的下标 ✅

大家好,我是你们的算法小伙伴。今天我们来练习一道字符串匹配 的经典简单题 ------LeetCode 28. 找出字符串中第一个匹配项的下标。这道题考察字符串子串匹配,是面试中常见的基础题,也是学习 KMP 算法的入门题。


题目描述

给你两个字符串 haystackneedle,请你在 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 <= 10^4
  • haystackneedle 仅由小写英文字符组成

解题思路

方法一:暴力匹配

  1. 遍历 haystack 中所有可能的起始位置 i(范围 [0, len(haystack)-len(needle)])。
  2. 对于每个 i,逐个字符比较 haystack[i:i+m]needlemneedle 长度)。
  3. 若完全匹配,直接返回 i;若遍历完都不匹配,返回 -1

方法二:KMP 算法

利用 "部分匹配表(LPS 数组)"避免重复比较,时间复杂度优化到 O (n+m),适合处理大数据量。

方法三:Java 内置方法

直接使用 String.indexOf() 方法,底层已做优化,代码最简洁。


代码实现

方法一:暴力匹配

复制代码
class Solution {
    public int strStr(String haystack, String needle) {
        int n = haystack.length();
        int m = needle.length();
        // 遍历所有可能的起始位置
        for (int i = 0; i <= n - m; i++) {
            int j = 0;
            // 逐个字符比较
            while (j < m && haystack.charAt(i + j) == needle.charAt(j)) {
                j++;
            }
            // 完全匹配,返回起始下标
            if (j == m) {
                return i;
            }
        }
        // 未找到匹配
        return -1;
    }
}

方法二:KMP 算法

复制代码
class Solution {
    public int strStr(String haystack, String needle) {
        int n = haystack.length();
        int m = needle.length();
        if (m == 0) return 0;
        
        // 1. 构建 LPS 数组(最长前缀后缀数组)
        int[] lps = new int[m];
        int len = 0; // 最长公共前后缀长度
        int i = 1;
        while (i < m) {
            if (needle.charAt(i) == needle.charAt(len)) {
                len++;
                lps[i] = len;
                i++;
            } else {
                if (len != 0) {
                    len = lps[len - 1];
                } else {
                    lps[i] = 0;
                    i++;
                }
            }
        }
        
        // 2. KMP 匹配
        i = 0; // haystack 指针
        int j = 0; // needle 指针
        while (i < n) {
            if (haystack.charAt(i) == needle.charAt(j)) {
                i++;
                j++;
            }
            if (j == m) {
                return i - j; // 找到匹配,返回起始下标
            } else if (i < n && haystack.charAt(i) != needle.charAt(j)) {
                if (j != 0) {
                    j = lps[j - 1]; // 回退到最长公共前后缀位置
                } else {
                    i++;
                }
            }
        }
        return -1;
    }
}

方法三:内置方法

复制代码
class Solution {
    public int strStr(String haystack, String needle) {
        return haystack.indexOf(needle);
    }
}

代码详解(暴力匹配示例 1 模拟)

示例 1:haystack = "sadbutsad", needle = "sad"

  • n = 9, m = 3,遍历 i 从 0 到 6:
    • i=0:比较 haystack[0] = 's'haystack[1] = 'a'haystack[2] = 'd',与 needle 完全匹配 → 返回 0

复杂度分析

方法 时间复杂度 空间复杂度 优点
暴力匹配 O(n*m) O(1) 代码简单,易理解
KMP 算法 O(n+m) O(m) 高效,适合大数据量
内置方法 O (n)(底层优化) O(1) 代码最简洁,面试推荐

总结

  1. 基础版:暴力匹配适合理解,代码简单,适合数据量小的场景。
  2. 进阶版:KMP 算法是字符串匹配的经典算法,核心是利用 LPS 数组避免重复比较,时间复杂度更优。
  3. 简洁版 :直接调用 indexOf(),在面试中是最快的写法,且底层已做优化。

这道题是字符串处理的入门题,掌握暴力匹配和 KMP 算法,能为后续学习更复杂的字符串算法打下基础。

今天的每日算法练习就到这里,我们明天再见!👋

相关推荐
椰羊~王小美2 小时前
随机数概念及算法
算法
阿Y加油吧2 小时前
算法实战笔记:LeetCode 169 多数元素 & 75 颜色分类
笔记·算法·leetcode
不要秃头的小孩2 小时前
力扣刷题——509. 斐波那契数
python·算法·leetcode·动态规划
We་ct3 小时前
LeetCode 120. 三角形最小路径和:动态规划详解
前端·javascript·算法·leetcode·typescript·动态规划
蒸汽求职3 小时前
破局“无效互面”:跨国大厂视角的工业级 Mock Interview 价值解析
缓存·面试·职场和发展·金融·notion
py有趣3 小时前
力扣热门100题之和为K的子数组
数据结构·算法·leetcode
hipolymers4 小时前
C语言怎么样?难学吗?
c语言·数据结构·学习·算法·编程
workflower5 小时前
机器人应用-楼宇室内巡逻
大数据·人工智能·算法·microsoft·机器人·动态规划·享元模式
ZPC82105 小时前
fanuc 机器人通过PR寄存器实现轨迹控制
人工智能·算法·计算机视觉·机器人