自习算法:LCS Problem

第一天自习: LCS Problem (Longest Common Subsequence)

  • 以下描述摘自演算法笔记:

在一堆 sequence 當中,每個 sequence 都有出現、最長的 subsequence ,就是「最長共同子序列」。
s1: 2 5 7 9 3 1 2
s2: 3 5 3 2 8
以上例來看, s1 和 s2 的 LCS 是 5 3 2 。這個例子恰恰好只有一個 LCS ,然而 LCS 可能同時有許多個,就像 LIS 一樣。
s1: a b c d b c e e a
s2: c a b d e f g a
s3: d c e a
以上例來看, s1 和 s2 和 s3 的其中一個 LCS 是 c e a ,另一個 LCS 是 dea.

解决方法:

  • 暴力法
    • 这个是几乎每一个问题都能够用到的方法,但是穷举法的代价就是并没有什么速度可言,时间复杂度随着数列数的增加而增加
  • 动态规划
    • 动态规划问题当然比较好,算法时间复杂度基本在O(n^2)左右

动态规划:(精华部分)

先贴计算LCS长度的代码:

 // 為了實作方便,從陣列的第1格開始存入序列。
int s1[7+1] = {0, 2, 5, 7, 9, 3, 1, 2};
int s2[5+1] = {0, 3, 5, 3, 2, 8};

// DP 的表格
int array[7+1][5+1];

void LCS()
{
    將 array[x][0] 和 array[0][x] 都設為 0 ;

for (int i = 1; i <= s1_length; i++)
    for (int j = 1; j <= s2_length; j++)
        if (s1[i] == s2[j])
            // 這裡加上的 1 是指 e1 的長度為 1
            array[i][j] = array[i-1][j-1] + 1;
        else
            array[i][j] = max(array[i-1][j], array[i][j-1]);

cout << "LCS 的長度是" << array[seq1_length][seq2_length];
}

然后是找出这个序列:

int s1[7+1] = {0, 2, 5, 7, 9, 3, 1, 2};
int s2[5+1] = {0, 3, 5, 3, 2, 8};

// DP 的表格
int array[7+1][5+1];

// 記錄這一格的最大值是從哪一格求得的
int prev[7+1][5+1];

void LCS()
{
    將 array[x][0] 和 array[0][x] 都設為 0 ;

for (int i = 1; i <= s1_length; i++)
    for (int j = 1; j <= s2_length; j++)
        if (s1[i] == s2[j])
        {
            // 這裡加上的 1 是指 e1 的長度為 1
            array[i][j] = array[i-1][j-1] + 1;
            prev[i][j] = 左上方;
        }
        else
        {
            if (array[i-1][j] < array[i][j-1])
            {
                array[i][j] = array[i][j-1];
                prev[i][j] = 左方;
            }
            else
            {
                array[i][j] = array[i-1][j];
                prev[i][j] = 上方;
            }
        }

cout << "LCS 的長度是" << array[s1_length][s2_length];

cout << "LCS 為 ";
print_LCS(s1_length, s2_length);
}

void print_LCS(int i, int j)
{
    // 第一個或第二個 sequence 為空的的時候就可停止了
    if (i==0 || j==0) return;

if (prev[i][j] == 左上方)
{
    print_LCS(i-1, j-1);
    cout << s1[i];  // 印出 LCS 的元素
}
else if (prev[i][j] == 上方)
    print_LCS(i-1, j);
else if (prev[i][j] == 左方)
    print_LCS(i, j-1);
}
  • 其实抛开代码,这个跟背包问题有点类似,就是填表,一个二维的array,人为的去填写的话,先把这个array填满,然后有三种情况:左,上和左上.只有左上才是要选的,否则的都不选取,然后将选取的pick出来就是LCS.

图片摘自七月

其实就是这幅图,填表,通过表格知道那个到底是选取了的.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值