当前位置:   article > 正文

代码随想录学习Day 33

代码随想录学习Day 33

动态规划理论基础

动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的。

例如:有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。动态规划中dp[j]是由dp[j-weight[i]]推导出来的,然后取max(dp[j], dp[j - weight[i]] + value[i])。但如果是贪心呢,每次拿物品选一个最大的或者最小的就完事了,和上一个状态没有关系。所以贪心解决不了动态规划的问题。

动态规划五部曲:

确定dp数组(dp table)以及下标的含义

确定递推公式

dp数组如何初始化

确定遍历顺序

举例推导dp数组

在代码中找问题的最好方式就是把dp数组打印出来,看看究竟是不是按照自己思路推导的!

509.斐波那契数

题目链接

讲解链接

递归解法:

  1. class Solution:
  2. def fib(self, n: int) -> int:
  3. if n == 0 or n == 1:
  4. return n
  5. else:
  6. return self.fib(n - 1) + self.fib(n - 2)

动态规划:

1.确定dp数组及其下标的含义:dp[i]的含义为第i个数的斐波那契数值是dp[i];

2.确定递推公式:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];

3.dp数组如何初始化:dp[0] = 0,dp[1] = 1;

4.确定遍历顺序:从递归公式dp[i] = dp[i - 1] + dp[i - 2]中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的;

5.举例推导dp数组:按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],当n为10的时候,dp数组应该是:0 1 1 2 3 5 8 13 21 34 55。

  1. class Solution:
  2. def fib(self, n: int) -> int:
  3. if n <= 1:
  4. return n
  5. dp = [0] * (n + 1) # 创建dp数组
  6. dp[0], dp[1] = 0, 1 # dp数组初始化
  7. for i in range(2, n + 1): # 从前向后遍历
  8. dp[i] = dp[i - 1] + dp[i - 2]
  9. return dp[n]

70.爬楼梯

题目链接

讲解链接

动规五部曲:

1.确定dp数组以及下标的含义:dp[i]爬到第i层楼梯,有dp[i]种方法;

2.确定递推公式:从dp[i]的定义可以看出,dp[i] 可以有两个方向推出来。首先是dp[i - 1],上i-1层楼梯,有dp[i - 1]种方法,那么再一步跳一个台阶就是dp[i]。还有就是dp[i - 2],上i-2层楼梯,有dp[i - 2]种方法,那么再一步跳两个台阶就是dp[i]。那么dp[i] = dp[i - 1] + dp[i - 2]

3.dp数组如何初始化:dp[i]的定义:爬到第i层楼梯,有dp[i]种方法。所以dp[1] = 1,dp[2] = 2,然后从i = 3开始递推;

4.确定遍历顺序:从递推公式dp[i] = dp[i - 1] + dp[i - 2]可以看出,遍历顺序一定是从前向后遍历的

5.举例推导dp数组:举例当n为5的时候,dp table(dp数组)应该是1 2 3 5 8.

  1. class Solution:
  2. def climbStairs(self, n: int) -> int: # 与斐波那契数基本一致
  3. if n <= 2:
  4. return n
  5. dp = [0] * (n + 1)
  6. dp[0], dp[1], dp[2] = 0, 1, 2
  7. for i in range(3, n + 1):
  8. dp[i] = dp[i - 1] + dp[i - 2]
  9. return dp[n]

746.使用最小花费爬楼梯

题目链接

讲解链接

动归五部曲:

1.确定dp数组及其下标含义:dp[i]表示的是爬到第i级台阶所需费用的最小值;

2.确定递推公式:dp[i - 1] 跳到 dp[i] 需要花费 dp[i - 1] + cost[i - 1]。dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]。因为要取最小值,所以公式为 dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);

3.dp数组如何初始化:dp[0] = 0,dp[1] = 0;

4.确定遍历顺序:因为dp[i]由dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组;

5.举例推导dp数组:例2对应的dp数组为[0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 6]。

  1. class Solution:
  2. def minCostClimbingStairs(self, cost: List[int]) -> int:
  3. dp = [0] * (len(cost) + 1) # 创建dp数组并初始化
  4. for i in range(2, len(cost) + 1): # 从前向后遍历
  5. dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]) # 递推公式
  6. return dp[-1] # 最后一项为爬到楼顶的消耗
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/555906
推荐阅读
相关标签
  

闽ICP备14008679号