最长公共子序列/子串

最长公共子序列

思路一

  • 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

代码

/**
 * @param {string} text1
 * @param {string} text2
 * @return {number}
 */
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开始

代码

/**
 * @param {string} text1
 * @param {string} text2
 * @return {number}
 */
var longestCommonSubsequence = function(text1, text2) {
    // dp[i][j]: text1以第i个字符结尾,text2以第j个字符结尾的最长公共子序列长度
    // if text1[i]==text2[j], dp[i][j] = dp[i-1][j-1] + 1;
    // if text1[i]!=text2[j], dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
    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);
    }
    // i, j指第i, j个字符
    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个字符为结尾的最长公共子串.。
    • 注意,这里的子串一定是以i,和j位置元素为结尾。
  • if str[i]==str[j], dp[i][j] = dp[i-1][j-1]+str[i];
  • if str[i]!=str[j], dp[i][j] = "";

代码

/**
 * longest common substring
 * @param str1 string字符串 the string
 * @param str2 string字符串 the string
 * @return string字符串
 */
function LCS( str1 ,  str2 ) {
    // write code here
    // 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] = "";
    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
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值