The cheapest way up a staircase
cost[i] is the cost of standing on step i. You may start on step 0 or step 1, and from
any step you climb one or two steps. Return the minimum total cost to get past the last step (to position
n).
Examples
| Input | Output | Why |
|---|---|---|
cost = [10,15,20] | 15 | Start on step 1 and climb two. |
cost = [1,100,1,1,1,100,1,1,100,1] | 6 | Avoid every 100. |
cost = [0,0] | 0 | Free. |
Constraints
- 2 ≤ cost.length ≤ 1000
- 0 ≤ cost[i] ≤ 999
Hints
Hint 1
To stand on step i you came from i − 1 or i − 2.
Hint 2
dp[i] = cost[i] + min(dp[i − 1], dp[i − 2]); dp[0] = cost[0], dp[1] = cost[1].
Hint 3
The top is reached from the last or second-to-last step: min(dp[n − 1], dp[n − 2]).
Where people lose marks
- Returning dp[n − 1] only: the top can be reached from step n − 2 as well.
- Forgetting that the start can be step 1, which makes dp[1] = cost[1] rather than cost[0] + cost[1].
Dry run on [1,100,1,1,1,100,1,1,100,1]
Read it one frame at a time, the way you would trace the code on paper in an interview. Each frame shows the state after the step it describes.
-
Step 1 / 9cost10100112131410051617100819dp101001·2·3·4·5·6·7·8·9
Base cases: dp[0] = 1, dp[1] = 100.
-
Step 2 / 9cost10100112131410051617100819dp10100122·3·4·5·6·7·8·9
Step 2: 1 + min(100, 1).
-
Step 3 / 9cost10100112131410051617100819dp1010012233·4·5·6·7·8·9
Step 3: 1 + min(2, 100).
-
Step 4 / 9cost10100112131410051617100819dp101001223334·5·6·7·8·9
Step 4: 1 + min(3, 2).
-
Step 5 / 9cost10100112131410051617100819dp1010012233341035·6·7·8·9
Step 5: 100 + min(3, 3).
-
Step 6 / 9cost10100112131410051617100819dp101001223334103546·7·8·9
Step 6: 1 + min(103, 3).
-
Step 7 / 9cost10100112131410051617100819dp10100122333410354657·8·9
Step 7: 1 + min(4, 103).
-
Step 8 / 9cost10100112131410051617100819dp101001223334103546571048·9
Step 8: 100 + min(5, 4).
-
Step 9 / 9cost10100112131410051617100819dp10100122333410354657104869
Step 9: 1 + min(104, 5). Past the top: min(6, 104) = 6.
How to think about it
Let dp[i] be the cheapest way to stand on step i. You arrive from one or two steps below, so
dp[i] = cost[i] + min(dp[i − 1], dp[i − 2]), with dp[0] = cost[0] and dp[1] = cost[1]
since you may start on either. The top is one or two steps past the last two steps, so the answer is the smaller of
their dp values. Only the last two values are ever read, so two variables replace the array.
Complexity. Time O(n) · Space O(1)
The solution, in six languages
Each one is compiled and run against the test table before it is published. Java is reviewed by hand.
def min_cost_stairs(cost):
two_back, one_back = cost[0], cost[1] # cheapest way to stand on steps i - 2 and i - 1
for c in cost[2:]:
two_back, one_back = one_back, c + min(one_back, two_back)
return min(one_back, two_back) # step past the top from either#include <algorithm>
#include <vector>
int solve(const std::vector<int>& cost) {
int twoBack = cost[0], oneBack = cost[1];
for (size_t i = 2; i < cost.size(); ++i) {
int here = cost[i] + std::min(oneBack, twoBack);
twoBack = oneBack;
oneBack = here;
}
return std::min(oneBack, twoBack);
}class Solution {
public int minCostStairs(int[] cost) {
int twoBack = cost[0], oneBack = cost[1];
for (int i = 2; i < cost.length; i++) {
int here = cost[i] + Math.min(oneBack, twoBack);
twoBack = oneBack;
oneBack = here;
}
return Math.min(oneBack, twoBack);
}
}function minCostStairs(cost) {
let twoBack = cost[0], oneBack = cost[1];
for (let i = 2; i < cost.length; i++) [twoBack, oneBack] = [oneBack, cost[i] + Math.min(oneBack, twoBack)];
return Math.min(oneBack, twoBack);
}fn solve(cost: &[i64]) -> i64 {
let (mut two_back, mut one_back) = (cost[0], cost[1]);
for &c in &cost[2..] {
let here = c + one_back.min(two_back);
two_back = one_back;
one_back = here;
}
one_back.min(two_back)
}solve :: [Int] -> Int
solve (a : b : rest) = uncurry min (foldl step (a, b) rest)
where step (twoBack, oneBack) c = (oneBack, c + min oneBack twoBack)
solve _ = 0
Variants to try
- Steps of 1, 2 or 3.
- Count the cheapest routes.
- Some steps are broken and cannot be stood on.
Next problems
Can you reach the last position?
nums[i] is the furthest jump from position i. Can you get from the first position to the last? A reachability DP that collapses to one variable.
Open the problem → Medium15 minLargest sum with no two chosen positions adjacent
Two states, one recurrence, O(1) memory. The example to reach for when someone asks you to explain dynamic programming.
Open the problem → Medium20 minWays to decode a string of digits
Letters are encoded as 1 to 26. Count the ways to read a string of digits back as letters: one digit or two at a time, with zeros as the trap.
Open the problem →Write a solution and run it against the real test table.
Keep going
Can you reach the last position?
nums[i] is the furthest jump from position i. Can you get from the first position to the last? A reachability DP that collapses to one variable.
Open the problem → Medium15 minLargest sum with no two chosen positions adjacent
Two states, one recurrence, O(1) memory. The example to reach for when someone asks you to explain dynamic programming.
Open the problem → Medium20 minWays to decode a string of digits
Letters are encoded as 1 to 26. Count the ways to read a string of digits back as letters: one digit or two at a time, with zeros as the trap.
Open the problem → Dynamic programmingThe pattern behind it
Write the recursion, notice the repeats, fill a table in an order that makes each entry final.
Read the pattern →Preparing for a real process? Quant interview preparation, or book a free 20-minute call.