. 找出字符串中第一个匹配项的下标 给你两个字符串 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 。
题目分析
本题要求在一个字符串(haystack)中找到另一个字符串(needle)的第一个匹配项的下标,若不存在则返回 -1。核心是实现字符串的匹配逻辑,需要考虑边界条件(如 needle 长度大于 haystack 时直接返回 -1)和逐字符比对的效率。
代码解析
你提供的代码是暴力匹配法(BF 算法),逻辑清晰且容易理解,以下是逐行解析:
cpp
运行
class Solution {
public:
int strStr(string s, string p) { // s对应haystack,p对应needle
int n = s.size(), m = p.size(); // n是主串长度,m是模式串长度
// 遍历主串的起始位置,i的上限是n-m(否则剩余字符不足匹配模式串)
for(int i = 0; i <= n - m; i++){
int j = i, k = 0; // j:主串当前比对位置,k:模式串当前比对位置
// 逐字符比对,直到模式串匹配完 或 字符不相等
while(k < m and s[j] == p[k]){
j++; // 主串指针后移
k++; // 模式串指针后移
}
// 若模式串全部匹配完成,说明找到第一个匹配项,返回起始下标i
if(k == m) return i;
}
// 遍历完所有可能位置都未匹配,返回-1
return -1;
}
};
关键要点
- 循环上限:
i <= n - m是核心优化,避免无效遍历(比如主串只剩 2 个字符,模式串有 3 个,无需继续)。 - 逐字符比对:内层
while循环逐个比对主串和模式串的字符,一旦不匹配则跳出,尝试下一个起始位置。 - 匹配成功判定:当
k == m时,说明模式串的所有字符都匹配完成,直接返回当前起始下标i(保证是第一个匹配项)。
示例验证
-
示例 1:
haystack = "sadbutsad", needle = "sad"-
n=9, m=3,i从 0 开始:i=0时,j=0, k=0,比对s[0]='s' == p[0]='s'→j=1, k=1;s[1]='a' == p[1]='a'→j=2, k=2;s[2]='d' == p[2]='d'→j=3, k=3;k==m,返回0,符合预期。
-
-
示例 2:
haystack = "leetcode", needle = "leeto"-
n=8, m=5,i只能遍历到8-5=3:i=0时,比对到s[4]='c'vsp[4]='o',不匹配;- 后续
i=1/2/3均无匹配,最终返回-1,符合预期。
-
复杂度分析
- 时间复杂度:最坏情况下(如主串是
aaaaa...b,模式串是aaaaab),时间复杂度为 O(n×m),其中n是主串长度,m是模式串长度。 - 空间复杂度:O(1),仅使用了常数个临时变量。
优化思路(KMP 算法)
如果想优化时间复杂度到 O(n+m),可以使用 KMP 算法(核心是利用模式串的前缀函数减少重复比对)。以下是 KMP 实现版本:
cpp
运行
class Solution {
public:
int strStr(string s, string p) {
int n = s.size(), m = p.size();
if (m == 0) return 0;
// 构建前缀函数(next数组)
vector<int> next(m, 0);
for (int i = 1, j = 0; i < m; i++) {
while (j > 0 && p[i] != p[j]) j = next[j - 1];
if (p[i] == p[j]) j++;
next[i] = j;
}
// KMP匹配
for (int i = 0, j = 0; i < n; i++) {
while (j > 0 && s[i] != p[j]) j = next[j - 1];
if (s[i] == p[j]) j++;
if (j == m) return i - m + 1; // 匹配完成,返回起始下标
}
return -1;
}
};
总结
你提供的暴力匹配代码逻辑正确、易于理解,能满足题目要求(即使在 1e4 长度的字符串下,暴力法也能通过测试,因为实际测试用例不会全是最坏情况)。如果追求更高效率,可以选择 KMP 算法。