四、Dynamic-programming algorithm Dynamic--LCS

(学习笔记,无什参考价值!)

1 问题

在这里插入图片描述

2 算法

2.1 Brute-force LCS algorithm

在这里插入图片描述

  • 检查每一个subsequence是否是 y y y的子列时,遍历 y y y的每一个元素,看是否依次可以全部覆盖subsequence所有元素,所以其复杂度为 O ( n ) O(n) O(n);

2.2 Dynamic-programming hallmark #1

  • 动态规划的第一特征–最优子结构,下面用定理的方式证明这种特征;
    在这里插入图片描述

  • 这个性质是说,一个规模稍大的最优解问题建立在一些规模较小的最优解问题基础之上,由此解决问题的思路就有两个方向:自顶向下的递归方式、自底向上的方式。
    在这里插入图片描述

  • 很容易可以推出下面的(数量上的)性质:
    在这里插入图片描述

  • 由上面的递归公式,首先想到的是使用递归实现:
    在这里插入图片描述

  • 下面用递归树分析递归实现的时间复杂度:
    在这里插入图片描述

  • 递归树的高度就是指数,所以时间复杂度是指数级别,和暴力解法没有什么大提高!

  • 从上面递归树图中观察到一个现象:递归树中存在大量重复的子问题,这些是导致递归算法龟速的原因,也是动态规划诞生的另外一个必要条件。

2.3 Dynamic-programming hallmark #2

  • 动态规划的第二特征–大量重复子问题
    在这里插入图片描述

  • 有了这个特征,此时有两条改进思路,一是在递归过程中,存储算过的每一个子问题。算法描述如下:

在这里插入图片描述

  • 另外一个改进思路是自底向上算法:
    在这里插入图片描述
  • 在上面自底向上的计算过程中,同时做了最优数值记录和最优路径记录这两件事,路径本质是:记录每一步由哪一个子问题得到父问题的解,路径的起点是(1,1),终点是(m,n),从终点到起点依照“来的时候做的箭头标记”,可以完整的回到起点,其中路径中标记’↘’路标的坐标点是最优解中的点。
  • 手工演示如下:
    在这里插入图片描述

2.4 打印最优解

  • 依照上面的分析可以很容易找到一个倒序的LCS,结合递归实现原理,正好可以正序打印出LCS,算法如下:
    在这里插入图片描述
  • 看这段代码,直觉上感觉还是倒序输出LCS,但是仔细考虑一下递归底层的运行过程,递归中的“递”就是入栈,递进;“归”就是出栈,回归,以倒序压入到栈中,以正序出栈;

3 代码实现

# -*- coding: utf-8 -*-
import numpy as np


def LCS_LENGTH(X, Y):
    m = len(X)
    n = len(Y)
    b = np.array([0] * (m * n)).reshape((m, n))
    c = np.array([0] * (m * n)).reshape((m, n))
    for i in range(1, m):
        c[i][0] = 0
    for j in range(0, n):
        c[0][j] = 0
    for i in range(1, m):
        for j in range(1, n):
            if X[i] == Y[j]:
                c[i][j] = c[i - 1][j - 1] + 1
                b[i][j] = 0
            elif c[i - 1][j] >= c[i][j - 1]:
                c[i][j] = c[i - 1][j]
                b[i][j] = '1'
            else:
                c[i][j] = c[i][j - 1]
                b[i][j] = '-1'
    return c, b


def PRINT_LCS(b, X, i, j):
    if i == 0 or j == 0:
        return
    if b[i][j] == 0:
        PRINT_LCS(b, X, i - 1, j - 1)
        print(X[i])
    elif b[i][j] == 1:
        PRINT_LCS(b, X, i - 1, j)
    else:
        PRINT_LCS(b, X, i, j - 1)


if __name__ == '__main__':
    X = ['x', 'A', 'B', 'C', 'B', 'D', 'A', 'B']
    Y = ['x', 'B', 'D', 'C', 'A', 'B', 'A']
    c, b = LCS_LENGTH(X, Y)
    PRINT_LCS(b, X, len(X) - 1, len(Y) - 1)

运行结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值