一、题目描述
给你两个字符串 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 <= 104haystack和needle仅由小写英文字符组成
二、思路分析
-
使用双指针的方式
i,j,i用来遍历haystack字符串,j用来匹配needle字符串 -
边界判断:检查
needle的长度,如果为 0,则直接返回 0,因为空字符串是任何字符串的子串 -
遍历
haystack字符串 -
匹配判断:
- 比较
haystack与needle是否匹配,如果匹配,则让两个指针都++,直到当j等于needleLen - 1,说明已经找到了完整的匹配子串,返回当前匹配子串的起始索引i - j - 如果不匹配,则
i需要回到上一次匹配的位置,然后 +1,从上次匹配的位置的下一个位置开始;j需要重置为 0,重新从needle的开头开始匹配
- 比较
-
最后如果不匹配返回 -1
这里的 i - j + 1不好理解:实际就是一旦发现不匹配了,不能草率的直接让 i++,需要有一个回溯的过程,所以需要回到上一次匹配的位置,然后 +1 从下一个位置开始,进行后续的匹配(参考测试4进行理解)
三、代码答案
/**
* @param {string} haystack
* @param {string} needle
* @return {number}
*/
var strStr = function (haystack, needle) {
const haystackLen = haystack.length;
const needleLen = needle.length;
if (needleLen === 0) return 0;
let i = 0;
let j = 0;
while (i < haystackLen) {
// 判断是否相等
if (haystack[i] === needle[j]) {
if (j === needleLen - 1) return i - j;
i++;
j++;
} else {
// i-j:将 i 移动到上一个匹配的位置
i = i - j + 1;
// 重置
j = 0;
}
}
return -1
};
// 测试1
console.log(strStr("hello", "ll")); // 2
// 测试2
console.log(strStr("sadbutsad", "sad")); // 0
// 测试3
console.log(strStr("leetcode", "leeto")); // -1
// 测试4
console.log(strStr("mississippi", "issip")); // 4