您现在的位置是:网站首页 > 最长公共子序列(LCS)的动态规划算法文章详情
最长公共子序列(LCS)的动态规划算法
陈川 【 JavaScript 】 30183人已围观
在计算机科学领域,最长公共子序列(Longest Common Subsequence, LCS)问题是一个经典的动态规划问题。该问题涉及找到两个序列中共同拥有的最长子序列。在解决LCS问题时,动态规划方法通常被采用,因为它允许我们通过构建一个表格来有效地解决问题,避免了重复计算,并最终通过回溯确定解。
问题定义
给定两个字符串X = X1...Xm
和Y = 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。
结论
通过动态规划方法解决最长公共子序列问题,不仅可以高效地找到解决方案,而且能够清晰地理解问题的递归结构,从而为更复杂的问题提供解决思路。
站点信息
- 建站时间:2017-10-06
- 网站程序:Koa+Vue
- 本站运行:
- 文章数量:
- 总访问量:
- 微信公众号:扫描二维码,关注我