实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置(从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = “hello”, needle = “ll”
输出: 2
示例 2:输入: haystack = “aaaaa”, needle = “bba”
输出: -1
说明:当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf()
定义相符。
方法一:子串逐一比较 - 线性时间复杂度
最直接的方法 - 沿着字符换逐步移动滑动窗口,将窗口内的子串与 needle 字符串比较。
var strStr = function(haystack, needle){
if (needle==="") return 0
for(var i=0;i<haystack.length;i++){
if(haystack[i]===needle[0]){
var flag = true;
for (var j=1;j<needle.length;j++){
if (haystack[i+j]!=needle[j]){
flag = false
break;
}
}
if (flag) return i
}
}
return -1
};
复杂度分析
时间复杂度:O((N−L)L),其中 N 为 haystack 字符串的长度,L 为 needle 字符串的长度。内循环中比较字符串的复杂度为 L,总共需要比较 (N - L) 次。
空间复杂度:O(1)
方法二:双指针 - 线性时间复杂度
上一个方法的缺陷是会将 haystack 所有长度为 L 的子串都与 needle 字符串比较,实际上是不需要这么做的。
首先,只有子串的第一个字符跟 needle 字符串第一个字符相同的时候才需要比较。
其次,可以一个字符一个字符比较,一旦不匹配了就立刻终止。
var strStr = function(haystack, needle) {
if(needle.length == 0) return 0;
let ph = 0,pn = 0,p;
while(ph <haystack.length-needle.length+1){
if(haystack[ph] == needle[pn]){
p = ph;
while(pn < needle.length && p < haystack.length && haystack[p] == needle[pn]){
p++;
pn++;
}
}
if(p - ph == needle.length) return ph;
else {
p = ph++;
pn = 0;
}
}
return -1;
};
复杂度分析
- 时间复杂度:最坏时间复杂度为 O((N−L)L),最优时间复杂度为 O(N)。
- 空间复杂度:O(1)
var strStr = function(haystack, needle) {
if(needle.length == 0) return 0;
for(let i = 0;i<haystack.length;i++){
if(haystack[i] = needle[0]){
if(haystack.slice(i,i+needle.length) == needle){
return i;
}
}
}
return -1;
};