您现在的位置是:网站首页 > 最长公共子序列(LCS)的动态规划算法文章详情

最长公共子序列(LCS)的动态规划算法

陈川 JavaScript 30183人已围观

在计算机科学领域,最长公共子序列(Longest Common Subsequence, LCS)问题是一个经典的动态规划问题。该问题涉及找到两个序列中共同拥有的最长子序列。在解决LCS问题时,动态规划方法通常被采用,因为它允许我们通过构建一个表格来有效地解决问题,避免了重复计算,并最终通过回溯确定解。

问题定义

给定两个字符串X = X1...XmY = Y1...Yn,求出它们的最长公共子序列长度以及该子序列本身。

动态规划解法

步骤一:初始化状态转移矩阵

创建一个二维数组dp,其中dp[i][j]表示字符串X的前i个字符与字符串Y的前j个字符之间的最长公共子序列的长度。

步骤二:填充状态转移矩阵

对于i从1到m,对于j从1到n

  • 如果Xi == Yj,则dp[i][j] = dp[i-1][j-1] + 1
  • 否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1])

步骤三:回溯获取最长公共子序列

dp[m][n]开始,回溯到dp[0][0],记录每次状态转移的路径,即当dp[i][j] != dp[i-1][j-1] + 1时,根据dp[i][j]来自dp[i-1][j]还是dp[i][j-1],来决定当前字符是否包含在LCS中。

示例代码(使用JavaScript)

function longestCommonSubsequence(X, Y) {
    let m = X.length;
    let n = Y.length;
    let dp = Array.from({length: m + 1}, () => Array(n + 1).fill(0));

    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            if (X[i - 1] === Y[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 = m, j = n;
    while (i > 0 && j > 0) {
        if (X[i - 1] === Y[j - 1]) {
            lcs.unshift(X[i - 1]);
            i--;
            j--;
        } else if (dp[i - 1][j] > dp[i][j - 1]) {
            i--;
        } else {
            j--;
        }
    }

    return {length: dp[m][n], sequence: lcs.join('')};
}

// 测试代码
const X = "ABCBDAB";
const Y = "BDCAB";
console.log(longestCommonSubsequence(X, Y));

输出解释

上述代码输出的结果是一个对象,包含了最长公共子序列的长度和子序列本身。对于示例输入X = "ABCBDAB"Y = "BDCAB",输出将是{length: 4, sequence: "BCAB"},表明最长公共子序列为BCAB,长度为4。

结论

通过动态规划方法解决最长公共子序列问题,不仅可以高效地找到解决方案,而且能够清晰地理解问题的递归结构,从而为更复杂的问题提供解决思路。

我的名片

网名:川

职业:前端开发工程师

现居:四川省-成都市

邮箱:chuan@chenchuan.com

站点信息

  • 建站时间:2017-10-06
  • 网站程序:Koa+Vue
  • 本站运行
  • 文章数量
  • 总访问量
  • 微信公众号:扫描二维码,关注我
微信公众号
每次关注
都是向财富自由迈进的一步