动态规划——最长公共子序列

动态规划——最长公共子序列

问题:

问题:给定2个序列X={x1 ,x2 ,…,xm}和Y={y1 ,y2 ,…,yn},找出X和Y的最长公共子序列。子序列和子串的区别:是否连续。

分析:

首先考虑蛮力法,求X和Y的所有公共子序列,找出最长的。判断X一个子序列是否是Y子序列时间O(n),X有2m个子序列,最坏情况下时间复杂度O(n2m)。

考虑使用动态规划算法求解:

——分析最优子结构:子结构由原序列尝试减少最后一个元素得到。设序列X={x1 ,x2 ,…,xm}和Y={y1 ,y2 ,…,yn}的最长公共子序列为Z={z1 ,z2 ,…,zk } ,则(a)若xm= yn,则zk=xm=yn,且zk-1是xm-1和yn-1的最长公共子序列。(b)若xm≠ yn且zk≠xm,则Z是xm-1和Y的最长公共子序列。©若xm≠ yn且zk≠yn,则Z是X和yn-1的最长公共子序列。

——建立递推关系:用c[i][j]记录序列Xi和Yj的最长公共子序列的长度。其中,Xi={x1 ,x2 ,…,xi};Yj={y1 ,y2 ,…,yj}。建立递推关系如下:c[i][j] = 0,i=0 or j=0;c[i][j] = c[i-1][j-1] + 1,i>0,j>0,xi=xj;c[i][j] = max{c[i][j-1],c[i-1][j]},i>0,j>0,xi!=xj;

——计算最优值:设x序列y序列的长度分别是m和n,则子问题共有mn个,搜索所有的子问题即可,需要记录最优解的话就需要额外的一个数组b[i][j],记录Xi={x1 ,x2 ,…,xi};Yj={y1 ,y2 ,…,yj}是由哪个子问题的解得到的,后续traceback即可。

——构造最优解:根据b[i][j]traceback即可。

代码:

#include <bits/stdc++.h>

using namespace std;

#define MAXN 105

// 求最优值,即各个子问题最长公共子序列的长度
// 输入:序列x,y,子问题最优值记录矩阵c,最优解记录矩阵b,x长度m,y长度n
void LCS(char x[],char y[],int c[][MAXN],int b[][MAXN],int m,int n){
    // 初始化最小子问题
    for(int i = 0;i <= m;i++)
        c[i][0] = 0;
    for(int i = 0;i <= n;i++)
        c[0][i] = 0;
    // 根据递推公式计算解空间
    for(int i = 1;i <= m;i++){
        for(int j = 1;j <= n;j++){
            if(x[i-1]==y[j-1]){
                c[i][j] = c[i-1][j-1] + 1;
                b[i][j] = 1;
            }else{
                if(c[i][j-1] > c[i-1][j]){
                    c[i][j] = c[i][j-1];
                    b[i][j] = 2;
                }else{
                    c[i][j] = c[i-1][j];
                    b[i][j] = 3;
                }
            }
        }
    }
}

// 根据记录矩阵b还原最优解
void traceback(int b[][MAXN],char x[],char y[],int m,int n){
    if(m==0||n==0){
        return;
    }
    if(b[m][n]==1){
        traceback(b, x, y, m-1, n-1);
        cout<<x[m-1]<<" ";
    }else if(b[m][n]==2){
        traceback(b, x, y, m, n-1);
    }else if(b[m][n]==3){
        traceback(b, x, y, m-1, n);
    }
}

int main(){
    int m = 7,n = 6;
    char x[7] = {'A','B','C','B','D','A','B'};
    char y[6] = {'B','D','C','A','B','A'};
    
    int b[MAXN][MAXN],c[MAXN][MAXN];
    memset(b, 0, sizeof(b));
    memset(c, 0, sizeof(c));
    
    LCS(x, y, c, b, m, n);
    
    traceback(b, x, y, m, n);
}

时间复杂度为O(mn,仅与问题输入规模有关)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值