前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动态规划算法练习 (1)

动态规划算法练习 (1)

作者头像
生信编程日常
修改2023-09-21 17:58:21
5410
修改2023-09-21 17:58:21
举报

动态规划(英语:Dynamic programming,简称DP)是一种在数学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。在生物信息领域,比如在序列比对的时候,就用到了动态规划的思想。在隐马尔科夫模型中的维特比 (Viterbi) 算法也使用了动态规划算法。

对于一个问题,我们分析出初始状态和递推公式是解出的关键。比如以下几个经典题目:

1. 爬楼梯 (https://leetcode.com/problems/climbing-stairs/)

有一座高度是10级台阶的楼梯,从下往上走,每跨一步只能向上1级或者2级台阶。求出一共有多少种走法。

这个问题仔细想想其实与斐波那契数列很像,同样可用递归求解。 假如最后我们已经爬上了10层,那么最后一个步骤走了要么一步, 要么两步。也就是说,我们到10层的走法,其实就是我们走到八层和九层的方法的和。即F(n) = F(n-2) + F(n-1)。

递归求解:

代码语言:javascript
复制
def climb(n):
    if n == 1:
        return 1
    elif n == 2:
        return 2
    else:
        return climb(n - 1) + climb(n - 2)

climb(10)

递归会很慢,浪费很多没必要的资源。可以考虑以下方法:

代码语言:javascript
复制
def climb(n):
    way = [0] * n
    way[0] = 1
    way[1] = 2
    for i in range(2, n):
        way[i] = way[i - 1] + way[i - 2]
    return way[n - 1]

# 或者 
def climb=(n):
    if n <= 2:
        return n
    else:
        a, b = 1, 2
        for i in range(n - 2):
            a, b = b, a + b
        return b

climb(10)
2. 使用最小花费爬楼梯 (https://leetcode.com/problems/min-cost-climbing-stairs/)

数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 cost[i](索引从0开始)。每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。(cost 的长度将会在 [2, 1000]。) 比如:

与上一个题有异曲同工之妙,其实其实本质上i位置的值就等于前一个和前两个中的最小值与这个位置的值的和,即f[i] = cost[i] + min(f[i-1], f[i-2])。

代码语言:javascript
复制
 def cal_cost(cost):
        dp = [0] * (len(cost) + 1)
        dp[0] = cost[0]
        dp[1] = cost[1]
        
        cost.append(0)
        for i in range(2, len(cost)):
            dp[i] = min(dp[i - 1], dp[i-2]) + cost[i]
            
        return dp[-1]
3. 打家劫舍 (https://leetcode.com/problems/house-robber/)

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

当我们偷窃到第i家的时候,所能偷到的就是一直到第i - 1家所偷到的与第i - 2家和第i家偷到的钱的和的最大值,即dp[i] = max(nums[i] + dp[i -2], dp[i-1])。

代码语言:javascript
复制
def rob(nums):
    size = len(nums)
    
    if size == 1:
        return nums[0]
    elif size == 2:
        return max(nums[0], nums[1])
    elif size == 0:
        return 0     
    else:
        dp = [0] * size
        dp[0], dp[1] = nums[0], max(nums[0], nums[1])

        for i in range(2, size):
            dp[i] = max(nums[i] + dp[i - 2], dp[i - 1])

        return dp[-1]

其实可以发现我们其实只用到了dp[i-2]与dp[i-1]的值,那么对上边的方法进行优化:

代码语言:javascript
复制
def rob(nums):
    now = last = 0
    for i in range(len(nums)):
        now, last = max(last + nums[i], now), now 
    return now 
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 爬楼梯 (https://leetcode.com/problems/climbing-stairs/)
  • 2. 使用最小花费爬楼梯 (https://leetcode.com/problems/min-cost-climbing-stairs/)
  • 3. 打家劫舍 (https://leetcode.com/problems/house-robber/)
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档