思路一
-
dp(s1, i, s2, j) 表示s1从i位置开始, s2从j位置开始 的最长公共子序列长度
-
如果s1[i]==s2[j],则s1[i]和s2[j]都在最长子序列中,dp(s1, i, s2, j) = dp(s1, i+1, s2, j+1)+1
-
如果s1[i]!=s2[j],则s1[i]或者s2[j]至少有一个不在最长子序列中,dp(s1, i, s2, j) = 以下三种情况的最大值
若s1[i]不在最长子序列中:dp(s1, i+1, s2, j)
若s2[j]不在最长子序列中:dp(s1, i, s2, j+1)
若s1[i]、s2[j]都不在最长子序列中:dp(s1, i+1, s2, j+1)
-
因为要求 最大 公共子序列长度,则第三种情况被前两种情况包含了,因此第三种情况可以去掉。
-
边界dp(s1,0,s2,0)=0
代码
var longestCommonSubsequence = function(text1, text2) {
let memo = new Array(text1.length);
for(let i=0; i<memo.length; i++){
memo[i] = new Array(text2.length).fill(-1);
}
return helper(text1, 0, text2, 0, memo);
};
var helper = function(text1, i, text2, j, memo) {
if(i>=text1.length || j>=text2.length){
return 0;
}
if(memo[i][j]!=-1){
return memo[i][j];
}
if(text1[i]==text2[j]){
memo[i][j] = helper(text1, i+1, text2, j+1, memo)+1;
}else{
memo[i][j] = Math.max( helper(text1, i+1, text2, j, memo), helper(text1, i, text2, j+1, memo) );
}
return memo[i][j]
}
思路二(动态规划)
dp[i][j]: text1以第i个字符结尾,text2以第j个字符结尾的最长公共子序列长度
s1[i-1]==s2[j-1]时,dp[i][j] = dp[i-1][j-1] + 1
s1[i-1]!=s2[j-1]时,dp[i][j] = max(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
i和j从1开始
代码
var longestCommonSubsequence = function(text1, text2) {
let m = text1.length;
let n = text2.length;
let dp = new Array(m+1);
for(let i=0; i<dp.length; i++){
dp[i] = new Array(n+1).fill(0);
}
for(let i=1; i<m+1; i++){
for(let j=1; j<n+1; 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-1][j], dp[i][j-1]);
}
}
}
return dp[m][n];
};
思路
dp[i][j]: 以str1第i个字符为结尾,str2第j个字符为结尾的最长公共子串.。
if str[i]==str[j], dp[i][j] = dp[i-1][j-1]+str[i];
if str[i]!=str[j], dp[i][j] = "";
代码
function LCS( str1 , str2 ) {
let m = str1.length;
let n = str2.length;
let dp = new Array(m+1);
let res = "";
for(let i=0; i<m+1; i++){
dp[i] = new Array(n+1).fill("");
}
for(let i=1; i<m+1; i++){
for(let j=1; j<n+1; j++){
if(str1[i-1]==str2[j-1]){
dp[i][j] = dp[i-1][j-1] + str1[i-1];
res = res.length < dp[i][j].length ? dp[i][j] : res;
}
}
}
return res;
}
module.exports = {
LCS : LCS
};