DP - 1D · Easy
LeetCode 746: Min Cost Climbing Stairs — solution
1D DP where the cost to reach each step is the cheaper of arriving from one or two steps below. O(n) time and O(1) space with two rolling variables.
Problem in plain words
Each stair i has a price cost[i] that you pay when you step off it. From any stair you may climb one or two stairs. You can begin on stair 0 or stair 1 for free, and the goal is to get past the last stair (the 'top', at index n). Find the cheapest total.
For example, with cost = [5, 2, 6], start on stair 1, pay 2, and jump two stairs to the top. Total: 2.
Intuition
To stand on stair i, your last move came either from stair i - 1 (paying its cost) or from stair i - 2 (paying that cost). Whichever of those two options is cheaper is the best way to reach i. Because each value only needs the two before it, this is the same rolling-window structure as the bottom-up Fibonacci DP lesson.
Approach
- State:
reach[i]is the minimum money spent to stand on stairi(withi = nmeaning the top). - Recurrence:
reach[i] = min(reach[i - 1] + cost[i - 1], reach[i - 2] + cost[i - 2]). - Base cases:
reach[0] = 0andreach[1] = 0, because you may start on either for free. - Order: compute
i = 2ton, keeping only the last two values. The answer isreach[n].
Dry run
Input: cost = [3, 1, 4, 1, 5], so the top is index 5.
| i | From i-1 | From i-2 | reach[i] |
|---|---|---|---|
| 0 | - | - | 0 |
| 1 | - | - | 0 |
| 2 | 0 + 1 = 1 | 0 + 3 = 3 | 1 |
| 3 | 1 + 4 = 5 | 0 + 1 = 1 | 1 |
| 4 | 1 + 1 = 2 | 1 + 4 = 5 | 2 |
| 5 (top) | 2 + 5 = 7 | 1 + 1 = 2 | 2 |
The best route starts on stair 1, pays 1 to reach stair 3, pays 1 again to jump to the top. Total 2.
Java solution
class Solution {
public int minCostClimbingStairs(int[] cost) {
int twoBack = 0, oneBack = 0; // reach[i-2], reach[i-1]
for (int i = 2; i <= cost.length; i++) {
int current = Math.min(oneBack + cost[i - 1], twoBack + cost[i - 2]);
twoBack = oneBack;
oneBack = current;
}
return oneBack;
}
}Python solution
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
two_back, one_back = 0, 0 # reach[i-2], reach[i-1]
for i in range(2, len(cost) + 1):
current = min(one_back + cost[i - 1], two_back + cost[i - 2])
two_back, one_back = one_back, current
return one_backComplexity
| Measure | Cost | Why |
|---|---|---|
| Time | O(n) | One constant-time step per stair. |
| Space | O(1) | Only the last two reach values are kept. |
Edge cases and common mistakes
- The top is not the last stair: the answer is for index
n, one past the end. Returningreach[n - 1]misses the final jump. - Two stairs only: with
cost = [a, b]the loop runs once and returnsmin(a, b), which is right. - Paying for the starting stair twice: in this formulation you pay a stair's cost when leaving it, never when arriving.
- Mixing formulations: another common version defines
dp[i] = cost[i] + min(dp[i-1], dp[i-2])and returnsmin(dp[n-1], dp[n-2]). Both are correct; just do not combine pieces of each.
