【代码随想录】动态规划1-基础
动态规划
动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的。
解题步骤:
- 确定 dp 数组(dp table)以及下标的含义
- 确定递推公式
- dp 数组如何初始化
- 确定遍历顺序
- 举例推导 dp 数组
509. 斐波那契数
link
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0,F(1) = 1, F(n) = F(n - 1) + F(n - 2),其中 n > 1。给你 n ,请计算 F(n) 。
思路
- 确定 dp 数组(dp table)以及下标的含义:第 i 个数的斐波那契数值是 dp[i]
- 确定递推公式:题目中已经告知 dp[i] = dp[i - 1] + dp[i - 2]
- dp 数组如何初始化:题目中也告知 dp[0] = 0, dp[1] = 1
- 确定遍历顺序:从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的
- 举例推导 dp 数组:
1 | class Solution: |
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
思路
- 确定 dp 数组(dp table)以及下标的含义:到达第 i 阶的走法为 dp[i]
- 确定递推公式:可以定义为 dp[i] = dp[i - 1] + dp[i - 2](dp[i - 1] 走一步,dp[i - 2] 走两步)
- dp 数组如何初始化:第 0 阶不走,可以定义为 0(dp[0] = 0),第一阶只有 1 种走法(dp[1] = 1),第二阶有 2 种(dp[2] = 2)
- 确定遍历顺序:从前往后
- 举例推导 dp 数组:
1 | class Solution: |
746. 使用最小花费爬楼梯
link
给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。
思路
- 确定 dp 数组(dp table)以及下标的含义:到达第 i 阶的最小花费
- 确定递推公式:可以定义为 dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])(dp[i - 1] 走一步,dp[i - 2] 走两步)
- dp 数组如何初始化:题目已经给出,可以从 0 或者 1 开始走,说明 dp[0] dp[1] 都是 0
- 确定遍历顺序:从前往后
- 举例推导 dp 数组:
1 | class Solution: |
62.不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
思路
- 确定 dp 数组(dp table)以及下标的含义:到达第 (i, j) 位置的方法数
- 确定递推公式:可以定义为 dp[i][j] = dp[i-1][j] + dp[i][j-1],要么从左边来,要么从上面来。注意考虑边界情况
- dp 数组如何初始化:可以定义为 1,这样 dp[0][1] 和 dp[1][0] 就可以使用递推公式来计算了
- 确定遍历顺序:从前往后
- 举例推导 dp 数组:
1 | class Solution: |
其实第一行(dp[0][:])和第一列(dp[:][0])只能为 1,所以可以从 1 开始遍历
数论思路(高中数学 😂)
一共需要 m - 1 个竖着走和 n - 1 个横着走,总共是 m + n - 2 个步骤。相当于是给 m + n - 2 个不同的数,随便取 m - 1 个数,有几种取法。