746. 使用最小花费爬楼梯
思路
1. 确定dp数组以及下标的含义
使用动态规划,就要有一个数组来记录状态,本题只需要一个一维数组dp[i]就可以了。
dp[i]的定义:到达第i台阶所花费的最少体力为dp[i]。
对于dp数组的定义,大家一定要清晰!
2.确定递推公式
可以有两个途径得到dp[i],一个是dp[i-1] 一个是dp[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 - 1]跳还是从dp[i - 2]跳呢?
一定是选最小的,所以dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
3.dp数组如何初始化
看一下递归公式,dp[i]由dp[i - 1],dp[i - 2]推出,既然初始化所有的dp[i]是不可能的,那么只初始化dp[0]和dp[1]就够了,其他的最终都是dp[0]dp[1]推出。
那么 dp[0] 应该是多少呢? 题目描述中明确说了 “你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。” 也就是说 到达 第 0 个台阶是不花费的,但从 第0 个台阶 往上跳的话,需要花费 cost[0]。
所以初始化 dp[0] = 0,dp[1] = 0;
4.确定遍历顺序
最后一步,递归公式有了,初始化有了,如何遍历呢?
因为是模拟台阶,而且dp[i]由dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组就可以了。
5.使用实例模拟
代码
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
n = len(cost)
if n <= 2:
return min(cost[0],cost[1])
dp = [0]*( n +1)
dp[0] = 0
dp[1] = 0
for i in range(2,n+1):
dpi = min(dp[0]+cost[i-2],dp[1]+cost[i-1])
dp[0] = dp[1]
dp[1] = dpi
return dp[1]
贪心与动态规划区分
- 贪心,每次找最快达到目标的途径,考虑局部最优,不影响全局
- 动态规划,英文:Dynamic Programming,简称DP,前一个状态由后一个推导出来,常见于重叠子问题,比如,01背包
补充
2.map(), filter(), 和 reduce()
这些不是列表的方法,而是内建函数,可以用来处理列表数据:
- map(function, iterable):将函数应用到迭代器的每个元素,并返回一个迭代器。
- filter(function,iterable):过滤掉那些不满足函数条件的元素,并返回一个迭代器。
- reduce(function, iterable):对迭代器中的元素累积地应用函数(需要从 functools 模块导入)。
使用 map 计算平方
numbers = [1, 2, 3, 4]
squares = list(map(lambda x: x**2, numbers)) # squares 将会是 [1, 4, 9, 16]
使用 filter 筛选出偶数
evens = list(filter(lambda x: x % 2 == 0, numbers)) # evens 将会是 [2, 4]
使用 reduce 计算乘积
product = reduce(lambda x, y: x * y, numbers) # product 将会是 24