当前位置: 首页 > news >正文

动态规划理论基础,LeetCode 509. 斐波那契数 LeetCode 70. 爬楼梯 LeetCode 746. 使用最小花费爬楼梯

动态规划理论基础

动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。

所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的。

动态规划五部曲:

  1.  确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

Dubug

  • 找问题的最好方式就是把dp数组打印出来,看看究竟是不是按照自己思路推导的!
  • 做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果。 然后再写代码,如果代码没通过就打印dp数组,看看是不是和自己预先推导的哪里不一样。 如果打印出来和自己预先模拟推导是一样的,那么就是自己的递归公式、初始化或者遍历顺序有问题了。 如果和自己预先模拟推导的不一样,那么就是代码实现细节有问题。

LeetCode 509. 斐波那契数

思路

动态规划五部曲:

1. 确定dp数组(dp table)以及下标的含义。
一个数组,下标表示序列从哪里开始。
2. 确定递推公式
F(n) = F(n-1) + F(n-2)
3. dp数组如何初始化
下标0和下标1需要进行默认初始化,后续下标为n的元素需要通过下标为n-1和n-2的元素相加得到。dp数组长度等于n+1。
4. 确定遍历顺序
遍历顺序:下标从小到大进行遍历。
5. 举例推导dp数组
print递推后dp数组

Code

class Solution(object):def fib(self, n):""":type n: int:rtype: int"""dp = [0] * (n+1)  ## dp数组的初始化,且确保总能获取到F(n),F(n)的最小数组长度为n+1if n >= 1:dp[1] = 1if n == 0:      ## 特殊情况处理return 0elif n == 1:return 1length = len(dp)for i in range(2,length):     ### 左闭右开,遍历顺序dp[i] = dp[i-1] + dp[i-2] ### 遍历公式 + dubug查看dp数组return dp[n]

LeetCode 70. 爬楼梯

思路

回溯算法也可以解决,但会存在超时的问题。Code如下:

class Solution(object):def climbStairs(self, n):""":type n: int:rtype: int"""self.path = []self.total = 0self.sum = 0nums = [1, 2]self.backtracking(nums, n, 0)return self.sumdef backtracking(self, num, n, start_index):if self.total == n:self.sum += 1return if self.total > n:return for i in range(start_index, len(num)):self.path.append(num[i])# print("self.path", self.path)self.total += num[i]# print("self.total", self.total)self.backtracking(num, n, 0)self.total -= num[i]self.path.pop()

这道题的题目关键不是在于排序组合的获取(即你走到这阶台阶的过程),而是在于迈向更高台阶方法数目和低台阶方法数目的联系。

台阶方法数目
1阶1种方法( [1] )
2阶2种方法( [1,1], [2] )
3阶3种方法( [1,1,1], [1,2], [2,1])
4阶5种方法( [1,1,1,1], [1,2,1], [2,1,1], [1,1,2], [2,2])
......

从上述方法数目我可以看得出到第N阶的方法总数F(N)其实就是F(N-1)+F(N-2) —— 递归公式。

为什么会有这种规律。因为迈的步子只为1和2,因此如果你迈的步子为2,那么从F(N-2)迈向F(N),可以通过只迈2步实现,因此F(N)的方法总数中包含了F(N-2)。另外,如果你迈的步子为1,那从F(N-1)迈向F(N)可以通过只迈一步实现,可以F(N)的方法总数中包含了F(N-1),这就是为什么是F(N) = F(N-1) + F(N-2)。

递归五部曲:

1. 确定dp数组(dp table)以及下标的含义。
下标为0,表示迈1阶。因此迈的阶数 = 下标 + 1。
2. 确定递推公式
F(N) = F(N-1) + F(N-2)
3. dp数组如何初始化
因为后续相加是涉及到N-1和N-2,因此前两个元素需要手动初始化。dp数组的长度 == 阶数(n)。
4. 确定遍历顺序
从前向后遍历更新dp数组。
5. 举例推导dp数组
print递推后dp数组

Code

class Solution(object):def climbStairs(self, n):""":type n: int:rtype: int"""dp = [0] * nif n == 1:return 1if n >= 1:dp[0] = 1   ## 迈向第一级台阶的方法数目dp[1] = 2   ## 迈向第二级台阶的方法数目length = len(dp)for i in range(2,length):dp[i] = dp[i-1] + dp[i-2]return dp[n-1]

其实递推公式和遍历顺序跟斐波那契数是一样的,只不过在数组长度初始化和前两个值的初始化上有区别。

LeetCode 746. 使用最小花费爬楼梯

容易陷入贪心的思路,即每次只与前面的元素的判断,通过大小来选择局部最优。如下所示:

[1,100,1000,200]。如果贪心思路的话,你前两个元素就会选择1,指针右移一位,后续选择100,指针右移后续选择200,这样的话总cost == 301,但实际上,从100可以直接到200,总cost == 300。

动规五部曲:

1. 确定dp数组(dp table)以及下标的含义。
dp[i]表示跳到第 i 个台阶时需要花费的cost。
2. 确定递推公式
dp[i] = min( dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
即判断表示从第i-1个台阶出发跳1个台阶的花费,和从i-2个台阶出发跳2个台阶的花费。第i-1个台阶和第i-2个台阶已经分别包含了之前跳到当前这个台阶的花费。
3. dp数组如何初始化
是跳的这个操作才需要花费,因此当处于第1个台阶和第2个台阶时,此时花费为0。因此dp[0] == dp[1] == 0
4. 确定遍历顺序
从前向后遍历更新dp数组。
5. 举例推导dp数组
print递推后dp数组

Code

class Solution(object):def minCostClimbingStairs(self, cost):""":type cost: List[int]:rtype: int"""### 到达超出数组长度的下标就是到达楼梯顶部了。length = len(cost)dp = [0] * lengthif length > 2:for i in range(2, length):dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])### 距离楼梯顶部差一个台阶 / 两个台阶时需要进行比较     one_step_cost = dp[length-1] + cost[length-1]two_step_cost = dp[length-2] + cost[length-2]if one_step_cost > two_step_cost:return two_step_costelse:return one_step_cost
http://www.lryc.cn/news/587149.html

相关文章:

  • 编译器优化——LLVM IR,零基础入门
  • 基础数论学习笔记
  • 每天学习一个Python第三方库之jieba库
  • vue中 js-cookie 用法
  • 深度学习算法:开启智能时代的钥匙
  • DVWA靶场通关笔记-XSS DOM(High级别)
  • 详解缓存淘汰策略:LFU
  • 初级网安作业笔记1
  • 3. 【Blazor全栈开发实战指南】--Blazor是什么?为什么选择Blazor?
  • [特殊字符]使用 Nginx 将 HTTP 重定向到 HTTPS
  • Spring-----MVC配置和基本原理
  • CD49.【C++ Dev】容器适配器模式
  • 一个链表节点构造函数的定义及使用
  • 如何将FPGA设计的验证效率提升1000倍以上(4)
  • Datawhale AI 夏令营【更新中】
  • 动态规划题解_零钱兑换【LeetCode】
  • 数学与应用数学核心课程有哪些?全文解析!
  • Cursor精准上下文指定
  • [Python 基础课程]字典
  • Spring AI 项目实战(十七):Spring Boot + AI + 通义千问星辰航空智能机票预订系统(附完整源码)
  • 12.3 安全内存区域划分
  • Kubernetes集群安装
  • Word中的批注显示与修订显示
  • 无需付费即可利用AI消除音频噪声和生成字幕
  • 云服务器的基础使用
  • 代码部落 20250713 CSP-J复赛 模拟赛
  • Java#为什么使用ThreadLocal传参而不是直接传参
  • 每天一个前端小知识 Day 30 - 前端文件处理与浏览器存储机制实践
  • 5.适配器模式
  • ClickHouse 分区机制详解:规则、合并与实践指南