文章目录
- ❇️Day 38 第九章 动态规划 part01
- ✴️今日任务
- ⏺️理论基础
- 1. 什么是动态规划
- 2. 动态规划题目类型
- 3. 误区
- 4. 动规五部曲
- 5. 如何debug
- ❇️509. 斐波那契数
- 随想录思路
- 自己的代码
- ❇️70. 爬楼梯
- 随想录思路
- 自己的代码
- ❇️746. 使用最小花费爬楼梯
- 随想录思路
- 自己的代码
❇️Day 38 第九章 动态规划 part01
✴️今日任务
今天正式开始动态规划!
- 理论基础
- 509.斐波那契数
- 70.爬楼梯
- 746.使用最小花费爬楼梯
⏺️理论基础
- 无论大家之前对动态规划学到什么程度,一定要先看 我讲的 动态规划理论基础。
- 如果没做过动态规划的题目,看我讲的理论基础,会有感觉 是不是简单题想复杂了?
- 其实并没有,我讲的理论基础内容,在动规章节所有题目都有运用,所以很重要!
- 如果做过动态规划题目的录友,看我的理论基础 就会感同身受了。
- 视频讲解:https://www.bilibili.com/video/BV13Q4y197Wg
- 文章链接:https://programmercarl.com/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
1. 什么是动态规划
动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。
2. 动态规划题目类型
- 动规基础
- 背包问题
- 打家劫舍
- 股票问题
- 子序列问题
3. 误区
误以为重点只在搞懂递推公式,好多知识点都没弄明白,代码AC了但下一题还是不会做
需要搞清楚基本的解题逻辑和步骤
动态规划重要的不仅仅是递推公式
4. 动规五部曲
- 确定dp数组的含义(以及下标的含义)
- 递推公式
- 想清楚dp数组如何初始化
- dp数组的遍历顺序
- 打印dp数组(找错误)
5. 如何debug
做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果。
然后再写代码,如果代码没通过就打印dp数组,看看是不是和自己预先推导的哪里不一样。
如果打印出来和自己预先模拟推导是一样的,那么就是自己的递归公式、初始化或者遍历顺序有问题了。
如果和自己预先模拟推导的不一样,那么就是代码实现细节有问题。
这样才是一个完整的思考过程,而不是一旦代码出问题,就毫无头绪的东改改西改改,最后过不了,或者说是稀里糊涂的过了。
❇️509. 斐波那契数
- 很简单的动规入门题,但简单题使用来掌握方法论的,还是要有动规五部曲来分析。
- 题目链接:https://leetcode.cn/problems/fibonacci-number/
- 视频讲解:https://www.bilibili.com/video/BV1f5411K7mo
- 文章链接:https://programmercarl.com/0509.%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0.html
好久没接触动规了,直接看视频熟悉一下
随想录思路
- 确定dp数组的含义(以及下标的含义)
dp[i]:第i个斐波那契数的值为dp[i] - 递推公式
dp[i] = dp[i - 1] + dp[i - 2] - 想清楚dp数组如何初始化
dp[0] = 0; dp[1] = 1; - dp数组的遍历顺序
从前向后遍历 - 打印dp数组(找错误)
自己的代码
class Solution {public int fib(int n) {int dp[] = new int[n + 1];//优化:if (n <= 1) return n; if(n == 0) return 0;if(n == 1) return 1;dp[0] = 0;dp[1] = 1;for (int i = 2; i <= n; i++) {dp[i] = dp[i - 1] + dp[i - 2];}//System.out.println(Arrays.toString(dp));return dp[n];}
}
❇️70. 爬楼梯
- 本题大家先自己想一想, 之后会发现,和 斐波那契数 有点关系。
- 题目链接:https://leetcode.cn/problems/climbing-stairs/
- 视频讲解:https://www.bilibili.com/video/BV17h411h7UH
- 文章链接:https://programmercarl.com/0070.%E7%88%AC%E6%A5%BC%E6%A2%AF.html
因为好久没接触动态规划,所以毫无头绪,直接看视频
随想录思路
一阶——1种
二阶——2种(1+1;2)
三阶——3种(因为一步只能上1阶or2阶,所以只能是从一阶走2步or从二阶走1步:1+2)
四阶——5种(只能是从二阶走2步or从三阶走1步:2+3)
所以等同于斐波纳契数
- 确定dp数组的含义(以及下标的含义)
dp[i]:上到第i个阶梯有dp[i]种方法 - 递推公式
dp[i] = dp[i - 1] + dp[i - 2] - 想清楚dp数组如何初始化
dp[0]无意义,所以直接从dp[1]开始
dp[1] = 1; dp[2] = 2; - dp数组的遍历顺序
从前向后遍历 - 打印dp数组(找错误)
自己的代码
class Solution {public int climbStairs(int n) {int dp[] = new int[n + 1];if(n == 1) return 1;dp[1] = 1;dp[2] = 2;for (int i = 3; i <= n; i++) {dp[i] = dp[i - 1] + dp[i - 2];}//System.out.println(Arrays.toString(dp));return dp[n];}
}
❇️746. 使用最小花费爬楼梯
- 这道题目力扣改了题目描述了,现在的题目描述清晰很多,相当于明确说 第一步是不用花费的。
- 更改题目描述之后,相当于是 文章中 「拓展」的解法
- 题目链接:https://leetcode.cn/problems/min-cost-climbing-stairs/
- 视频讲解:https://www.bilibili.com/video/BV16G411c7y
- 文章链接:https://programmercarl.com/0746.%E4%BD%BF%E7%94%A8%E6%9C%80%E5%B0%8F%E8%8A%B1%E8%B4%B9%E7%88%AC%E6%A5%BC%E6%A2%AF.html
随想录思路
- 确定dp数组的含义(以及下标的含义)
dp[i]表示到i层最少需要花费的钱,i最大是cost.length也就是最顶层 - 递推公式
与上题思想一样
dp[i] = Math.min(dp[i - 2] + cost[i - 2], dp[i - 1] + cost[i - 1]); - 想清楚dp数组如何初始化
- dp[0] = 0
- dp[1] = 0
- dp数组的遍历顺序
从前往后遍历 - 打印dp数组(找错误)
自己的代码
class Solution {public int minCostClimbingStairs(int[] cost) {int dp[] = new int[cost.length + 1];dp[0] = 0;dp[1] = 0;for (int i = 2; i < dp.length; i++) {dp[i] = Math.min(dp[i - 2] + cost[i - 2], dp[i - 1] + cost[i - 1]);}//System.out.println(Arrays.toString(dp));return dp[cost.length];}
}