返回

从复杂到简单、易懂清晰的LeetCode-28解析

前端

从复杂到简单,LeetCode-28详解

算法概述

LeetCode-28: 实现strStr()函数,该函数接受两个字符串参数haystack和needle,并返回needle在haystack中的第一个出现位置。如果needle不在haystack中,则返回-1。

暴力匹配法

暴力匹配法是最简单、最直观的算法,但也是最慢的算法。其思想是,将needle逐个字符与haystack进行比较,如果发现匹配,则继续比较后续字符,直到needle所有字符都匹配成功或haystack结束为止。如果在haystack中没有找到与needle匹配的子串,则返回-1。

function strStr(haystack, needle) {
  if (needle === '') {
    return 0;
  }
  for (let i = 0; i <= haystack.length - needle.length; i++) {
    let found = true;
    for (let j = 0; j < needle.length; j++) {
      if (haystack[i + j] !== needle[j]) {
        found = false;
        break;
      }
    }
    if (found) {
      return i;
    }
  }
  return -1;
}

Knuth-Morris-Pratt(KMP)算法

KMP算法是一种高效的字符串匹配算法,它通过预处理needle字符串,构造一个next数组,来减少字符串比较次数。next数组的每个元素next[i]表示needle子串的前i个字符的最长公共前缀和后缀的长度。

function strStr(haystack, needle) {
  if (needle === '') {
    return 0;
  }
  const next = getNextArray(needle);
  let i = 0;
  let j = 0;
  while (i < haystack.length) {
    if (haystack[i] === needle[j]) {
      i++;
      j++;
      if (j === needle.length) {
        return i - j;
      }
    } else if (j > 0) {
      j = next[j - 1];
    } else {
      i++;
    }
  }
  return -1;
}

function getNextArray(needle) {
  const next = new Array(needle.length).fill(0);
  next[0] = -1;
  let i = 0;
  let j = -1;
  while (i < needle.length - 1) {
    if (j === -1 || needle[i] === needle[j]) {
      i++;
      j++;
      next[i] = j;
    } else {
      j = next[j];
    }
  }
  return next;
}

实践建议

  1. 在编写算法时,应该先考虑最简单、最直观的算法。如果该算法无法满足性能要求,再考虑使用更复杂的算法。
  2. 在学习算法时,应该先理解算法的思想和原理,再考虑算法的具体实现。
  3. 在练习算法时,应该选择不同难度的算法,并逐步提高难度。

扩展阅读

  1. LeetCode-28: Implement strStr()
  2. KMP算法