返回

动态规划之最长公共子序列--JavaScript实现

前端

本文将介绍一个经典的动态规划问题--最长公共子序列(LCS),并提供一个 JavaScript 实现。

前言

在前面两篇文章中,我们讲解了 01 背包问题和最少硬币找零问题。现在,让我们继续探索另一个经典的动态规划问题——最长公共子序列 (LCS)。如果您还没看过前两篇文章,可以点击下面的链接:

什么是最长公共子序列?

最长公共子序列 (LCS) 是两个字符串中最长的子序列,这个子序列由两个字符串中相同的字符组成,并且保持彼此之间的相对顺序。例如,字符串 "ABCD" 和 "ACED" 的最长公共子序列是 "AC",因为它是这两个字符串中最长的子序列,由相同的字符组成,并且保持相对顺序。

最长公共子序列的应用

LCS 有着广泛的应用,包括:

  • 代码对比:LCS 可以用于比较两个代码文件或程序,并找到它们的相似之处。
  • 文本编辑:LCS 可以用于在文本编辑器中提供建议,或者在搜索引擎中进行模糊搜索。
  • 生物信息学:LCS 可以用于比较基因序列,并找到它们之间的相似之处。

动态规划算法

LCS 可以使用动态规划算法来求解。动态规划是一种解决复杂问题的技术,它将问题分解成更小的子问题,并逐步解决这些子问题,最终得到最终结果。

JavaScript 实现

下面是使用 JavaScript 实现的最长公共子序列算法:

function lcs(str1, str2) {
  // 创建动态规划表
  let dp = Array(str1.length + 1).fill(0).map(() => Array(str2.length + 1).fill(0));

  // 填写动态规划表
  for (let i = 1; i <= str1.length; i++) {
    for (let j = 1; j <= str2.length; j++) {
      if (str1[i - 1] === str2[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1] + 1;
      } else {
        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
      }
    }
  }

  // 获取最长公共子序列
  let lcs = "";
  let i = str1.length;
  let j = str2.length;
  while (i > 0 && j > 0) {
    if (str1[i - 1] === str2[j - 1]) {
      lcs = str1[i - 1] + lcs;
      i--;
      j--;
    } else if (dp[i - 1][j] > dp[i][j - 1]) {
      i--;
    } else {
      j--;
    }
  }

  return lcs;
}

console.log(lcs("ABCD", "ACED")); // "AC"

常见问题

  • 如何解决字符串长度过长的问题?

如果字符串长度过长,可以使用滚动数组来优化动态规划表。滚动数组只需要存储当前行和前一行的数据,从而大大减少了内存的使用。

  • 如何处理重复的字符?

如果字符串中存在重复的字符,可以使用哈希表来存储每个字符的位置。这样,在填写动态规划表时,就可以快速找到相同字符的位置,从而减少计算量。

结语

最长公共子序列是一个经典的动态规划问题,在许多领域都有着广泛的应用。通过使用动态规划算法,我们可以高效地求解 LCS。在本文中,我们介绍了 LCS 的概念、应用和 JavaScript 实现,并提供了解决常见问题的提示。