746. 使用最小花费爬楼梯
题目描述:
数组的每个索引作为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 costi。
每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。
您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。
示例 1:
输入: cost = [10, 15, 20]
输出: 15
解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15。
示例 2:
输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出: 6
解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6。
注意: cost 的长度将会在 [2, 1000]。 每一个 cost[i] 将会是一个Integer类型,范围为 [0, 999]。
解题
一、分析题目——最优子结构性质
对于每一个台阶,从底部到达其位置时所消耗的体力都必须是最少的
换句话说,每一个台阶都可以作为一“顶层台阶”
二、由该性质考虑到动态规划,尝试解题
1.划分阶段k——楼梯
每层楼梯对应不同的阶段,具体映射为k=cost列表索引
2.确定k阶段的状态变量x(k)——子最优解
与楼梯k有关的初始变量为cost值,但我们需要的x(k)是到达k阶楼梯到最优解
3.确定决策变量u(k)
决策变量应该与与楼梯k有关的初始变量有关(这个“有关”在一定程度上保证了无后效性)
事实上,u(k)=cost
4.确定状态转移方程x(k+1)=T(x(k),u(k))
既然已经判断出问题具有最优子结构性质,那也不难看出x(k)等于x(k-2)+cost[k-2]与x(k-1)+cost[k-1]中较小的那一个
即:
x(k)=min(x(k-2)+cost[k-2], x(k-1)+cost[k-1])
5.勿忘起始量
由于可以选择下标 0或1 作为初始阶梯,因此有
x(0)=x(1)=0
三、码代码
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
1.找k(因为存在顶层阶梯,所以上线为cost表长+1)
n = len(cost)
2.创建列表(因为存在顶层阶梯,所以上线为cost表长+1)
x = [0]*(n+1)
3.循环,填表,返回答案
for k in range(2,n+1):
x[k]=min(x(k-2)+cost[k-2], x(k-1)+cost[k-1])
return x[n]
完整代码
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
n = len(cost)
x = [0]*(n+1)
for k in range(2,n+1):
x[k]=min(x(k-2)+cost[k-2], x(k-1)+cost[k-1])
return x[n]
四、分析
1.时间复杂度O(n)
遍历cost
2.空间复杂度O(n)
x列表长n+1
五、优化
通过滚动列表优化空间复杂度
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
n = len(cost)
prev = curr = 0
for i in range(2, n + 1):
nxt = min(curr + cost[i - 1], prev + cost[i - 2])
prev, curr = curr, nxt
return curr