【经典动态规划问题】最长公共子序列LCS

目录

题目

题目分析

状态

边界值讨论

其他情况讨论

代码实现


从题目出发分析如何用动态规划求解最长公共子序列问题

题目

给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共子序列。

给定两个字符串AB,同时给定两个串的长度nm,请返回最长公共子序列的长度。保证两串长度均小于等于300。

测试样例:

"1A2C3D4B56",10,"B1D23CA45B6A",12
返回:6

题目分析

状态

dp[i][j],表示A[0,...i]和B[0,...j]的最长公共子序列长度。

边界值讨论

当i = 0时,dp[i][j]求的是A[0]和B[0,...j]的最长公共子序列长度,遍历B数组,如B[k] == A[0],也就是在B中找到了等于A[0]的值,最长公共子序列就是A[0],则dp[0][k,k+1,...m] = 1;

同理,当j = 0时,dp[i][j]求的是A[0,...i]和B[0]的最长公共子序列长度,遍历A数组,如A[t] == B[0],最长公共子序列就是B[0],则dp[t,t+1,...n][0] = 1;

其他情况讨论

求一般情况下的dp[i][j],只可能出现两种情况:

1.如果A[i] == B[j],dp[i][j] = dp[i-1][j-1]+1; 如‘ABCD’和‘ABDD’的最长公共子序列长度等于‘ABC’和‘ABD’的最长公共子序列长度+1,因为末尾元素D一定会包含在'ABCD'和'ABDD'的最长公共子序列中。

2.如果A[i]!=B[j],那么,A[0,...i]和B[0,...j]的最长公共子序列要么从A[0,..i]和B[0,...j-1]中取得,要么从A[0,..i-1]和B[0,...j]中取得;比较两个值中的最大值,即为dp[i][j]的值;如‘ABCD’和‘ABD4’中最长公共子序列的长度等于‘ABC’和‘ABD4'的最长公共子序列长度,要么等于‘ABCD’和‘ABD’的最长公共子序列长度,我们只需要取最大值即可。

代码实现

class LCS {
public:
    int findLCS(string A, int n, string B, int m) {
        // write code here
       //dp[i][j]表示A[0,...i]和B[0,...j]的最长公共子序列的长度
        int dp[301][301] = {0};
   for(int i = 0;i<n;i++){//第一列中,找出A[i] = B[0],dp[i][0] = 1,且dp[i+1,...n][0] = 1;
    
       if(A[i]==B[0]) //
       {
           for(int j = i;j<n;j++){
               dp[j][0] = 1;
           }
       }
   }
       
      for(int i = 0;i<m;i++){//第一行中,找出A[0] = B[i],dp[0][i] = 1,且dp[0][i+1,...m] = 1;
    
       if(A[0]==B[i]) //
       {
           for(int j = i;j<m;j++){
               dp[0][j] = 1;
           }
       }
   }
   //接下来考虑一般情况,dp[i][j]可能来自哪些情况:
      // A[i] != B[j] ,A[0...i]和B [0,...j-1]的最长公共子序列为dp[i][j-1]
     //如果A[i] == B[j],dp[i][j] = dp[i-1][j-1]+1
     // A[i] != B[j] ,A[0...i-1]和B [0,...j]的最长公共子序列为dp[i-1][j]
   int max = 0;
   for(int i = 1;i<n;i++){
       for(int j = 1;j<m;j++){
           if(A[i] == B[j])
               max= dp[i-1][j-1]+1;
           else{
               max = (dp[i][j-1] > dp[i-1][j] ? dp[i][j-1]: dp[i-1][j]);
           }
           dp[i][j] = max;
            
       }
   }
    return dp[n-1][m-1];
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值