【leetcode】28. 找出字符串中第一个匹配项的下标

47 阅读2分钟

leetcode-8.png

看见题目,一眼用indexOf,但是这样子貌似就没有做题的必要了

indexOf

var strStr = function(haystack, needle) {
    return haystack.indexOf(needle)
};

暴力破解

var strStr = function (haystack, needle) {
    let n = haystack.length
    let m = needle.length
    for (let i = 0; i <= n - m; ++i) {
        if (needle === haystack.slice(i, i + m)) {
            return i
        }
    }
    return -1
};
var strStr = function (haystack, needle) {
    let i = 0,
        j = 0;
    while (i < haystack.length && j < needle.length) {
        if (haystack[i] !== needle[j]) {
            i = i - j + 1;
            j = 0;
        } else {
            i++;
            j++;
        }
        if (j === needle.length) {
            return i - needle.length;
        }
    }
    return -1;
};

KMP算法

错误代码

var strStr = function (haystack, needle) {
    let i = 0,
        j = 0;
    while (i < haystack.length && j < needle.length) {
        if (haystack[i] !== needle[j]) {
            j = 0;
            i++;
        } else {
            i++;
            j++;
        }
        if (j === needle.length) {
            return i - needle.length;
        }
    }
    return -1;
};

image.png
对于上面的代码,可以看到,其实可以通过很多测试用例,主要的错误在于i的位置如何重置的这个问题
i如果要暴力穷举的话,那么就要在上次的开始的地方的下一位,也就是 i = i - j + 1,这个位置上
但是此时i的位置是直接i++,没有把前面区间穷举
在下面这个测试用例里面可以看到,此时ij指向的地方不想等,那么就要挪动i,恢复j = 0

     i
mississippi
 issip
     j

所以,从上面这段错误的代码,以及通过的测试用例里面可以看到,主要看i如何到下一个位置。
对于暴力穷举来说,肯定不会漏掉,但是要节约时间,那么就要看i如何抉择了

正确代码

var strStr = function (haystack, needle) {
    let n = haystack.length
    let m = needle.length
    let lps = new Array(m).fill(0)
    let j = 0
    // 计算next数组
    for (let i = 1; i < m; ++i) {
        while (j > 0 && needle[i] !== needle[j]) j = lps[j - 1]
        if (needle[i] === needle[j]) j++
        lps[i] = j
    }
    j = 0
    for (let i = 0; i < n; ++i) {
        // 回溯
        while (j > 0 && needle[j] !== haystack[i]) j = lps[j - 1]
        if (needle[j] === haystack[i]) j++
        // 返回起始位置
        if (j === m) return i - m + 1
    }
    return -1
};