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

最长公共子序列
1.问题的理解与描述

最长公共子序列(LCS)问题形式化为:

输入:序列X = <x1, x2, ..., xm>Y = <y1, y2, ..., yn>
输出:X与Y的一个最长公共子序列Z。

  1. 最优子结构与子问题的重叠
    定理3-1(最长公共子序列的最优子结构)
    X = <x1, x2, ..., xm>Y = <y1, y2, ..., yn>为两个序列,并设Z = <z1, z2, ..., zk>为X 和Y的任一LCS。
    (1)若xm = yn,则zk = xm = yn且Zk-1是Xm-1和Yn-1的一个LCS。
    (2)若xm ≠ yn,则zk ≠ xm蕴含着Z是Xm-1和Y的一个LCS。
    (3)若xm ≠ yn,则zk ≠ yn蕴含着Z是X 和Yn-1的一个LCS。

设c[i, j]为子序列Xi和Yj的LCS的长度。根据最长公共子序列问题的最优子结构得出下列递归式:
这里写图片描述
eg:
这里写图片描述

3.算法的伪代码描述

LCS-LENGTH (X, Y)
1 m ← length[X]
2 n ← length[Y]
3 for i ← 1 to m
4   do c[i, 0] ← 0  
5 for j ← 0 to n
6   do c[0, j] ← 0 
7 for i ← 1 to m
8   do for j ← 1 to n
9       do if xi = yj
10          then c[i, j] ← c[i - 1, j - 1] + 1
11          else if c[i - 1, j]  c[i, j - 1]
12                  then c[i, j] ← c[i - 1, j]
13                  else c[i, j] ← c[i, j - 1]
15 return c

4.构造一个最优解

PRINT-LCS(c, X, Y, i, j)
1 if i = 0 or j = 0
2   then return
3 if xi = yj
4   then PRINT-LCS (c, X, Y, i - 1, j - 1)
5       print xi
6   elseif c[i - 1, j]  c[i, j - 1]
7       then PRINT-LCS (c, X, Y, i - 1, j)
8       else PRINT-LCS (c, X, Y, i, j - 1)

5.算法的运行时间

过程LCS-LENGTH的主体是第7~8行两重嵌套的for循环,容易看出其时间复杂度为T(m, n)= Θ(mn),其中m,n分别为X和Y的长度。而过程PRINT-LCS的时间复杂度为T(m, n)= Θ(m+n)。

6 代码实现:

#ifndef _LCS_H
#define _LCS_H
#include<iostream>
using namespace std;

template<typename Iterator>
int* lcsLength(Iterator x, Iterator y, int m, int n)
{
    int i, j;
    int*c = new int[(m + 1)*(n + 1)];
    for (i = 1; i <= m; i++)
        c[i*(n + 1)] = 0;//c[i,0]=0
    for (j = 0; j <= n; j++)
        c[j] = 0;//c[0,j]=0;
    for (i = 1; i <= m; i++)
        for (j = 1; j <= n; j++)
            if (*(x + i-1) == *(y + j-1))//x[i]=y[j]
                c[i*(n + 1) + j] = c[(i - 1)*(n + 1) + j - 1] + 1;//c[i,j]=c[i-1,j-1]
            else if (c[(i - 1)*(n + 1) + j] >= c[i*(n + 1) + j - 1])//c[i-1,j]>=c[i,j-1]
                c[i*(n + 1) + j] = c[(i - 1)*(n + 1) + j];
            else
                c[i*(n + 1) + j] = c[i*(n + 1) + j - 1];
    return c;

}
template<typename Iterator>
void printLcs(int *c, int n, Iterator x, Iterator y, int i, int j)
{
    if (i == 0 || j == 0)
        return;
    if (*(x + i - 1) == *(y + j - 1))
    {
        printLcs(c, n, x, y, i - 1, j - 1);
        cout << *(x + i - 1);
    }
    else if (c[(i - 1)*(n + 1) + j] >= c[i*(n + 1) + j - 1])
        printLcs(c, n, x, y, i - 1, j);
    else
        printLcs(c, n, x, y, i, j - 1);

}
#endif 
#include <cstdlib>
#include "lcs.h"

int main(int arge, char** argv)
{
    char*x = "ACCGGTCGAGTGCGCGGAAGCCGGCCGAA";
    char*y = "GTCGTTCGGAATGCCGTTGCTCTGTAAA";

    int *c;
    c = lcsLength(x, y, 29, 28);
    printLcs(c, 28, x, y, 29, 28);
    cout << endl;
    delete[]c;

    system("pause");
    return EXIT_SUCCESS;
}

运行结果:
这里写图片描述

参考:徐子珊–《算法设计、分析与实现:C、C++和 Java》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值