The problem. cost[i] is the cost of stepping on step i; once you pay it you may climb 1 or 2 steps. You can start on step 0 or step 1, and the top is one step past the last index. Return the minimum total cost to reach the top.
cost = [10, 15, 20] -> 15
cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] -> 6Let reach[i] be the cheapest total paid to arrive at step i (not yet paying cost[i]). Starting is free, so reach[0] = reach[1] = 0. You arrive at step i from step i − 1 (having paid cost[i − 1]) or from step i − 2 (having paid cost[i − 2]): reach[i] = min(reach[i−1] + cost[i−1], reach[i−2] + cost[i−2]). The answer is reach[n] — the top. It's Climbing Stairs with min instead of +.
function minCostClimbingStairs(cost) { const memo = new Map(); const reach = (i) => { // cheapest way to arrive at step i if (i <= 1) return 0; // you may start on step 0 or 1 if (memo.has(i)) return memo.get(i); const best = Math.min(reach(i - 1) + cost[i - 1], reach(i - 2) + cost[i - 2]); memo.set(i, best); return best; }; return reach(cost.length); // the top is past the last step}Time O(n), space O(n) for the memo and the call stack.
Each step keeps the cheaper of its two ways to arrive.
function minCostClimbingStairs(cost) { const n = cost.length; const reach = new Array(n + 1).fill(0); // reach[0] = reach[1] = 0: start for free for (let i = 2; i <= n; i++) { reach[i] = Math.min(reach[i - 1] + cost[i - 1], // from one step below reach[i - 2] + cost[i - 2]); // or from two below } return reach[n]; // the top}Time O(n), space O(n).
function minCostClimbingStairs(cost) { let twoBelow = 0, oneBelow = 0; // reach[i - 2], reach[i - 1] for (let i = 2; i <= cost.length; i++) { [twoBelow, oneBelow] = [oneBelow, Math.min(oneBelow + cost[i - 1], twoBelow + cost[i - 2])]; } return oneBelow;}Time O(n), space O(1).
reach[n − 1] is a classic off-by-one.[1, 100, 1, 1, 1, 100, 1, 1, 100, 1]: 6.reach[i] = min over j in 1..k of reach[i − j] + |h[i] − h[i − j]|.