题目
题目链接:leetcode-cn.com/leetbook/re…
题解
题目是字符串匹配,数据结构的经典题型,一般教材上都会提供两种算法,BF 解法 和 KMP 解法;
1、暴力(BF)解法
/**
* @param {string} haystack
* @param {string} needle
* @return {number}
*/
var strStr = function(haystack, needle) {
const hLen = haystack.length,
nLen = needle.length;
if(nLen === 0) {
return 0;
}
if(nLen <= hLen) {
let i = j = 0;
while(i < nLen && j < hLen) {
if(haystack[j] === needle[i]) {
i++;
j++;
}else {
j = j - i + 1;
i = 0;
}
}
if(i === nLen) {
return j - i;
}
}
return -1;
};
2、KMP 解法
kmp 的原理是利用子串的特性(前缀和后缀有多少相等,算法中表现为 next 数组),使指向主串的指针不用回溯, kmp 的重点:
- 理解子串的 next 数组的含义和求 next 数组;
- 匹配时指向子串的下标应该怎样利用 next 数组变换;
/**
* @param {string} haystack
* @param {string} needle
* @return {number}
*/
var strStr = function(haystack, needle) {
let hLen = haystack.length;
let nLen = needle.length;
if(nLen > hLen) {
return -1;
}
if(nLen === 0) {
return 0;
}
let next = new Array(nLen).fill(0); // 使用fill构造一个数组
// 求 next 数组
for(let i = 1;i < nLen;i++) {
for(let m = 1;m <= i;m++){
let n = 0;
let nex = 0;
while((m + n)<=i && needle[n] === needle[m+n]) { // 使用 m+n , 而改变 m
n++;
nex++;
}
if((m + n) > i) {
next[i] = nex;
break; // 记住要break
}
}
}
// 匹配字符串
let j = 0;
for(let i = 0;i < hLen;i++) { // 这里是小于 hLen,因为完全有可能出现 hLen-nLen < i < hLen 的一轮循环
let flag = 0;
while(j < nLen) {
if(haystack[i] === needle[j]) {
i++;
j++;
flag = 1;
}else {
break;
}
}
if(nLen === j) {
return i - j;
}else if(0 === j) { // 处理 j === 0 时,访问 next[j] 越界问题;
continue;
}else {
j = next[j-1]; // 匹配的重点,借助 next 数组改变子串的下标 j,而不用回溯主串下标 i
i--; // 重点,如果到了这里一定是要把 i 减 1,以保持下一轮还是和这个为匹配的 haystack[i] 比较
}
}
return -1;
};
3、直接用 JS 提供的 API
这是一个非常快捷,并且会使程序时空复杂度非常低的方法;
因为那些 JS 引擎都是大神搞出来的,他们一般都是以最优的算法去实现 JS 的 api;
但是如果是学习算法和练习算法的话并不推荐这样做,因为这样并不能使我们的算法能力得到提高;
var strStr = function(haystack, needle) {
return haystack.indexOf(needle);
};
大家如果有更好的思路和解法,欢迎大家一起来讨论啊~
这是使用 JavaScript 对 LeetCode《初级算法》的每道题的总结和实现的其中一篇,汇总篇在这里: