题目链接: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
?仅由小写英文字符组成
文章讲解:代码随想录
视频讲解:帮你把KMP算法学个通透!(理论篇)
思路:外层循环遍历字符串,内层循环判断是否匹配。
/**
* @param {string} haystack
* @param {string} needle
* @return {number}
*/
var strStr = function(haystack, needle) {
for (let i = 0; i < haystack.length - needle.length + 1; i++) {
let j = i;
let flag = true;
for (let k = 0; k < needle.length; k++) {
if (haystack[j++] !== needle[k]) {
flag = false;
break;
}
}
if (flag) {
return i;
}
}
return -1;
};
分析:时间复杂度为 O(n2),空间复杂度为 O(1)。
思路:使用 KMP 算法来进行字符串模式匹配,也是这道题目的标解。先计算出 next 数组(即子串最长公共前后缀的前缀表),再借助 next 数组进行模式匹配。
/**
* @param {string} haystack
* @param {string} needle
* @return {number}
*/
var strStr = function(haystack, needle) {
// 计算前缀表
const next = [0];
// i 为后缀末尾,j 为前缀末尾
let j = 0;
for (let i = 1; i < needle.length; i++) {
while (j > 0 && needle[i] !== needle[j]) {
j = next[j - 1];
}
if (needle[j] === needle[i]) {
j++;
}
next[i] = j;
}
// 字符串模式匹配
j = 0;
for (let i = 0; i < haystack.length; i++) {
while (j > 0 && haystack[i] !== needle[j]) {
j = next[j - 1];
}
if (haystack[i] === needle[j]) {
j++;
}
if (j === needle.length) {
return i - needle.length + 1;
}
}
return -1;
};
分析:设原字符串长度为 n,匹配的模式串长度为 m,时间复杂度为 O(n + m),空间复杂度为 O(m)。
学习了 KMD 算法,写代码还不熟练,需要多多练习。