返回

剑指Offer 04:经典动态规划,从零到精通

前端

最长公共子序列(Longest Common Subsequence, 简称LCS)问题在LeetCode上是一个非常经典且重要的题目,它属于动态规划类型的算法问题。动态规划是一种解决复杂问题的一种非常有效的方法,它可以将复杂问题分解成一系列小问题,然后逐步求解这些小问题,最后将小问题的解组合起来就得到大问题的解。

LCS问题可以表述为:给定两个字符串,找出这两个字符串的最长公共子序列。所谓最长公共子序列,是指这两个字符串中出现的相同字符序列的最长长度。例如,对于字符串“ABCD”和“ACED”,它们的最长公共子序列是“AC”,长度为2。

LCS问题在计算机科学中有着广泛的应用,它可以用来比较两个字符串的相似性,也可以用来解决字符串匹配问题。在LeetCode上,LCS问题也是一道非常常见的题目,它经常出现在字符串章节中。

解决LCS问题,我们可以使用动态规划的方法。动态规划的思路是:将复杂问题分解成一系列小问题,然后逐步求解这些小问题,最后将小问题的解组合起来就得到大问题的解。对于LCS问题,我们可以将问题分解成一系列子问题:

  1. 对于字符串“ABCD”和“ACED”中的第一个字符“A”和“A”,它们的LCS长度为1。
  2. 对于字符串“ABCD”和“ACED”中的前两个字符“AB”和“AC”,它们的LCS长度为2。
  3. 对于字符串“ABCD”和“ACED”中的前三个字符“ABC”和“ACE”,它们的LCS长度为3。
  4. 对于字符串“ABCD”和“ACED”中的四个字符“ABCD”和“ACED”,它们的LCS长度为4。

以此类推,我们可以求出字符串“ABCD”和“ACED”中所有子问题的LCS长度。最后,将这些子问题的LCS长度组合起来,就得到字符串“ABCD”和“ACED”的最长公共子序列长度。

在代码中,我们可以使用一个二维数组来存储子问题的LCS长度。二维数组的每一行对应着字符串“ABCD”的一个前缀,每一列对应着字符串“ACED”的一个前缀。二维数组中的每一个元素存储着对应的前缀的LCS长度。

def lcs(s1, s2):
  m, n = len(s1), len(s2)
  dp = [[0] * (n + 1) for _ in range(m + 1)]

  for i in range(1, m + 1):
    for j in range(1, n + 1):
      if s1[i - 1] == s2[j - 1]:
        dp[i][j] = dp[i - 1][j - 1] + 1
      else:
        dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

  return dp[m][n]


if __name__ == "__main__":
  s1, s2 = "ABCD", "ACED"
  print(f"最长公共子序列长度:{lcs(s1, s2)}")

上面代码的时间复杂度为O(mn),其中m和n分别为字符串“ABCD”和“ACED”的长度。空间复杂度为O(mn),其中m和n分别为字符串“ABCD”和“ACED”的长度。

希望这篇文章对您有所帮助。如果您有任何问题,请随时提出。