前端算法锦囊-KMP算法

73 阅读2分钟

实现 strStr()(Implement strStr())

题目描述:

实现 strStr() 函数。给定两个字符串 haystackneedle,在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1

示例:

输入:haystack = "hello", needle = "ll"
输出:2

输入:haystack = "aaaaa", needle = "bba"
输出:-1

解题思路:

  1. 暴力匹配法

    • 遍历 haystack 字符串,逐个字符与 needle 进行比较。
    • 时间复杂度:O((n-m)*m),其中 n 是 haystack 长度,m 是 needle 长度。
  2. KMP 算法

    • 利用部分匹配表(Partial Match Table)优化匹配过程。
    • 时间复杂度:O(n+m),空间复杂度:O(m)。

代码实现(暴力匹配法):

function strStr(haystack, needle) {
    if (needle === "") return 0; // 空字符串返回 0
    
    const n = haystack.length;
    const m = needle.length;
    
    for (let i = 0; i <= n - m; i++) {
        let j = 0;
        while (j < m && haystack[i + j] === needle[j]) {
            j++;
        }
        if (j === m) return i; // 完全匹配
    }
    
    return -1; // 未找到
}

// 测试
console.log(strStr("hello", "ll")); // 输出 2
console.log(strStr("aaaaa", "bba")); // 输出 -1

代码实现(KMP 算法):

function strStr(haystack, needle) {
    if (needle === "") return 0;
    
    const n = haystack.length;
    const m = needle.length;
    
    // 构建部分匹配表
    const lps = buildLPS(needle);
    
    let i = 0, j = 0;
    while (i < n) {
        if (haystack[i] === needle[j]) {
            i++;
            j++;
            if (j === m) return i - j; // 完全匹配
        } else if (j > 0) {
            j = lps[j - 1]; // 利用部分匹配表回退
        } else {
            i++;
        }
    }
    
    return -1;
}

function buildLPS(needle) {
    const lps = new Array(needle.length).fill(0);
    let len = 0, i = 1;
    
    while (i < needle.length) {
        if (needle[i] === needle[len]) {
            len++;
            lps[i] = len;
            i++;
        } else if (len > 0) {
            len = lps[len - 1];
        } else {
            lps[i] = 0;
            i++;
        }
    }
    
    return lps;
}

// 测试
console.log(strStr("aabaaabaaac", "aabaaac")); // 输出 4
console.log(strStr("mississippi", "issip")); // 输出 4

复杂度分析:

  • 暴力匹配法
    • 时间复杂度:O((n-m)*m)
    • 空间复杂度:O(1)
  • KMP 算法
    • 时间复杂度:O(n+m)
    • 空间复杂度:O(m)

总结:

  1. 暴力匹配法简单直观,适合处理小规模字符串匹配
  2. KMP 算法通过预处理模式串,优化了匹配效率,适合处理大规模字符串匹配
  3. 在实际面试中,可以先实现暴力解法,再优化为KMP算法