每天学习一点算法 2025/12/03
题目:实现 strStr()
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。
如果 needle 不是 haystack 的一部分,则返回 -1 。
-
这种问题最简单的方法就是暴力枚举,直接枚举出
haystack中所有与needle相同长度的字符串,看是否有与needle相等的字符串即可。function strStr(haystack: string, needle: string): number { const hayLen = haystack.length; const needleLen = needle.length; // 空needle返回0 if (needleLen === 0) return 0; // needle比haystack长,直接返回-1 if (needleLen > hayLen) return -1; for (let i = 0; i <= hayLen - needleLen; i++) { let match = true; // 逐字符对比,避免切片创建临时字符串 for (let j = 0; j < needleLen; j++) { if (haystack[i + j] !== needle[j]) { match = false; break; // 不匹配直接跳出内层循环,减少对比次数 } } if (match) return i; } return -1; } -
还有一个方法就是KMP(Knuth-Morris-Pratt)算法,这个算法的核心就是在已经完成部分匹配子串中找到公共的前缀和后缀,下一次匹配从后缀的下一位开始匹配,这里举个栗子吧,好理解一点。
假设:主串
haystack = "ABABABC",模式串needle = "ABABC"-
初始:
i=0,j=0; -
haystack[0] = A == needle[0] = A→i=1,j=1; -
haystack[1] = B == needle[1] = B→i=2,j=2; -
haystack[2] = A == needle[2] = A→i=3,j=3; -
haystack[3] = B == needle[3] = B→i=4,j=4; -
haystack[4] = A != needle[4] = C这个时候遇到不匹配字符时,KMP和普通解法的区别就来了普通解法:
i = 1,j = 0,继续匹配KMP:因为已匹配的字符串
ABAB拥有公共的前后缀AB,我们可以从i = 5,j = 3继续匹配 -
现在对比
haystack[4] = A == needle[2] = A→i=5,j=3; -
haystack[5] = B == needle[3] = B→i=6,j=4; -
haystack[6] = C == needle[4] = C→i=7,j=5;对比完成
算法的大概思想是明白了,但是怎么实现呢?其他步骤都还好,关键在于怎么找到公共的前后缀。
因为是在已匹配成功的字串中寻找公共前后缀,所以我们只需把
needle每个子串的公共前后缀情况记录下来就行了,这里为needle生成「部分匹配表(LPS 数组)」—— 该数组存储了模式串每个位置的「最长前缀后缀匹配长度」。// 生成部分匹配表(Longest Prefix Suffix) function getLPS(needle: string): number[] { const len = needle.length; const lps = new Array(len).fill(0); let length = 0; // 最长匹配前缀的长度 for (let i = 1; i < len; ) { if (needle[i] === needle[length]) { length++; lps[i] = length; i++; } else { if (length > 0) { length = lps[length - 1]; // 回退长度 } else { lps[i] = 0; i++; } } } return lps; }然后就是遍历
haystack开始匹配function strStr(haystack: string, needle: string): number { const hayLen = haystack.length; const needleLen = needle.length; if (needleLen === 0) return 0; if (needleLen > hayLen) return -1; // 预处理needle,生成部分匹配表(最长前缀后缀匹配长度) const lps = getLPS(needle); let i = 0; // haystack指针 let j = 0; // needle指针 while (i < hayLen) { if (haystack[i] === needle[j]) { i++; j++; if (j === needleLen) { return i - j; // 匹配成功,返回起始索引 } } else if (j > 0) { // 不匹配时,根据lps回退needle指针(避免重复对比) j = lps[j - 1]; } else { i++; } } return -1; } -
-
叽里咕噜那么一长篇说啥呢?跟我的
indexOf说去吧// String.prototype.indexOf() function strStr(haystack: string, needle: string): number { return haystack.indexOf(needle) }
题目来源:力扣(LeetCode)

1万+

被折叠的 条评论
为什么被折叠?



