最长公共子序列(Longest Common Subsequence, 简称 LCS)是非常经典的二维动态规划,大部分比较困难的字符串问题都和这个问题一个套路,穷举+剪枝
思路:
第一步 要明确 dp 数组的含义
对于两个字符串的动态规划问题,一般都需要一个二维的 dp 数组
其中 dp[i][j] 的含义是:对于 string1[0, ......, i-1] 和 string2[0, ......, j-1],它们的最长公共子序列长度是 dp[i][j]
比如对于字符串 string1="abcde" string2="aceb"
一般要构造这样的 DP 表
dp[2][4] = 2 的含义就是: 对于 "ac" 和 "babc",它们的LCS长度是 2
如果想自己练习填写动态规划表格,可以在这里练习动态规划表格练习地址
根据这个定义,最终想得到的答案应该是 dp[3][6]
第二步 定义 base case
让索引为 0 的行和列表示空串,dp[0][…] 和 dp[...][0] 都应该初始化为 0, 这就是 base case
第三步 状态转移方程
这个问题具体是求 string1 和 string2 的最长公共子序列 LCS,对于 string1 和 string2 中的每一个字符,有两种选择:要么在 LCS 中,要么不在。
如何知道 string1[i] 和 string2[j] 是否在 LCS 中?
【留坑以后填之我看懂了但还不会解释】
(function(){
var longestCommonSubsequence = function (text1, text2) {
const m = text1.length;
const n = text2.length;
// dp数组m+1行n+1列,初始化为0,此时基础情况dp[0][...] 和 dp[...][0]也一并初始化为0
const dp = Array.from(Array(m+1), () => Array(n+1).fill(0));
console.log(dp);
for(let i = 1; i <= m; i++){
for(let j = 1; j <= n; j++){
if(text1[i - 1] == text2[j -1]){
dp[i][j] = dp[i -1][j -1] + 1;
} else {
dp[i][j] = Math.max(dp[i][j-1], dp[i-1][j]);
}
}
}
return dp[m][n];
};
longestCommonSubsequence("abcde", "ace")
}())