746. Min Cost Climbing Stairs* (使用最小花费爬楼梯)

​https://leetcode.com/problems/min-cost-climbing-stairs/​

题目描述

You are given an integer array ​​cost​​​ where ​​cost[i]​​​ is the cost of ​​i​​th step on a staircase. Once you pay the cost, you can either climb one or two steps.

You can either start from the step with index ​​0​​​, or the step with index ​​1​​.

Return the minimum cost to reach the top of the floor.

Example 1:

Input: cost = [10,15,20]
Output: 15
Explanation: Cheapest is: start on cost[1], pay that cost, and go to the top.

Example 2:

Input: cost = [1,100,1,1,1,100,1,1,100,1]
Output: 6
Explanation: Cheapest is: start on cost[0], and only step on 1s, skipping cost[3].

Constraints:

  • ​2 <= cost.length <= 1000​
  • ​0 <= cost[i] <= 999​

代码实现

我觉得这道题有意思的地方在于, 每次去写它总认为自己会写错. 今天才明白, 之所以会产生这样的想法, 是因为我之前并没有将求解方法纳入现有的思考体系中. 之前在 ​​746. Min Cost Climbing Stairs*​​ 写的状态方程虽然简洁, 但感觉不符合我现在的思考方式.

本题采用动态规划求解, 使用 ​​dp[i]​​​ 表示达到 ​​i​​​ 时所需要付出的最小代价. 假设 ​​cost​​​ 数组的大小为 ​​N​​​, 最终的目标就是跳到第 ​​N​​​ 个位置上, 所付出的代价就是 ​​dp[N]​​​. 根据题意, 当你位于第 ​​i​​​ 个位置时, 付出当前位置的花费 ​​cost[i]​​​, 就可以跳一步或者两步. 那么要跳到第 ​​i​​​ 个位置上时, 要么一开始就位于第 ​​i - 1​​​ 的位置上, 然后付出 ​​cost[i - 1]​​​ 的代价跳一步到达第 ​​i​​​ 个位置; 要么一开始位于第 ​​i - 2​​​ 的位置上, 然后付出 ​​cost[i - 2]​​​ 的代价跳两步到达第 ​​i​​​ 个位置;
综上, 状态转移方程呼之欲出:

dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])

要确定初始状态, 题目中说可以从第 ​​0​​​ 个位置和第 ​​1​​ 个位置开始起跳, 那么:

dp[0] = 0;
dp[1] = 0;

再次注意 ​​dp[i]​​​ 的含义是到达 ​​i​​​ 时所需要付出的最小代价, 该位置上的花费 ​​cost[i]​​​ 指的是你要离开 第 ​​i​​​ 个位置时需要付出的代价, 由于我们可以直接从第 ​​0​​​ 个位置和第 ​​1​​​ 个位置开始起跳, 所以它们的初始值均设置为 ​​0​​​. 最后我们只需要返回 ​​dp[N]​​ 就可以求解, 代码如下:

class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int N = cost.size();
vector<int> dp(N + 1, 0);
for (int i = 2; i <= N; ++ i)
dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
return dp[N];
}
};

注意题目中说了数组的大小至少为 ​​2​​​, 所以 ​​N < 2​​​ 的情况不用考虑. 写到这, 代码还不算完, 还需要考虑能否进一步优化. 观察到 ​​dp[i]​​​ 的结果只和 ​​dp[i - 1]​​​ 和 ​​dp[i - 2]​​​ 有关, 似乎不需要使用 ​​vector​​​ 来记录所有历史结果, 只需要使用变量 ​​dp0 = dp[i - 2], dp1 = dp[i - 1]​​​ 来保留历史状态, 同时不断维护 ​​dp0​​​ 和 ​​dp1​​ 的状态.

class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int N = cost.size();
int dp0 = 0, dp1 = 0, dp2 = 0;
for (int i = 2; i <= N; ++ i) {
dp2 = min(dp1 + cost[i - 1], dp0 + cost[i - 2]);
dp0 = dp1;
dp1 = dp2;
}
return dp2;
}
};

另外可以看看下面 “类似的题”, 均采用相同的思路就可以求解.

类似的题