返回

算法题打卡第二十八天:LeetCode28题,找出字符串中第一个匹配项的下标

后端

LeetCode 28:在字符串中查找第一个匹配项

算法简介

在 LeetCode 的第 28 题中,我们被要求找到一个模式字符串在给定字符串中的第一个匹配项的下标。如果模式字符串不存在于目标字符串中,则返回 -1。

暴力匹配法

暴力匹配法是一种简单直观的算法。它从目标字符串的开头开始,逐个字符地与模式字符串进行比较。如果前 n 个字符匹配,则模式字符串被找到。否则,算法继续比较前 n+1 个字符。

代码示例:

def find_first_match(string, pattern):
  """
  暴力匹配法找出字符串中第一个匹配项的下标。

  Args:
    string: 字符串。
    pattern: 模式字符串。

  Returns:
    第一个匹配项的下标。如果模式字符串不存在于字符串中,则返回-1。
  """

  for i in range(len(string) - len(pattern) + 1):
    if string[i:i + len(pattern)] == pattern:
      return i

  return -1

KMP 算法

KMP(Knuth-Morris-Pratt)算法是一种更高效的字符串匹配算法。它使用一个称为失败函数的预处理表来避免不必要的比较。失败函数保存了模式字符串中每个前缀与后缀的最大匹配长度。

代码示例:

def find_first_match_kmp(string, pattern):
  """
  KMP算法找出字符串中第一个匹配项的下标。

  Args:
    string: 字符串。
    pattern: 模式字符串。

  Returns:
    第一个匹配项的下标。如果模式字符串不存在于字符串中,则返回-1。
  """

  # 构造失败函数。
  failure_function = [0] * len(pattern)
  for i in range(1, len(pattern)):
    j = failure_function[i - 1]
    while j > 0 and pattern[i] != pattern[j]:
      j = failure_function[j - 1]
    if pattern[i] == pattern[j]:
      j += 1
    failure_function[i] = j

  # 匹配字符串。
  i = 0
  j = 0
  while i < len(string):
    if string[i] == pattern[j]:
      i += 1
      j += 1
    else:
      if j > 0:
        j = failure_function[j - 1]
      else:
        i += 1

    if j == len(pattern):
      return i - len(pattern)

  return -1

性能对比

暴力匹配法的复杂度为 O(n^2),其中 n 是目标字符串的长度。KMP 算法的复杂度为 O(n),在效率上优于暴力匹配法。

常见问题解答

  • Q:如何判断模式字符串不存在于目标字符串中?

    • A:如果查找算法返回 -1,则表示模式字符串不存在于目标字符串中。
  • Q:暴力匹配法和 KMP 算法的区别是什么?

    • A:暴力匹配法逐个字符地比较,而 KMP 算法使用失败函数来避免不必要的比较。
  • Q:哪种算法更适合处理大量数据?

    • A:KMP 算法由于其更低的复杂度,更适合处理大量数据。
  • Q:失败函数是如何工作的?

    • A:失败函数保存了模式字符串中每个前缀与后缀的最大匹配长度。它用于跳过模式字符串中已匹配过的字符,提高匹配效率。
  • Q:在 LeetCode 中解决此问题时需要注意什么?

    • A:注意目标字符串和模式字符串的边界条件,并考虑特殊情况,例如模式字符串为空的情况。