Post

LC 746 - Min Cost Climbing Stairs

LC 746 - Min Cost Climbing Stairs

Question

You are given an integer array cost where cost[i] is the cost of ith 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:

1
2
Input: cost = [10,15,20]
Output: 15

Explanation: You will start at index 1.

  • Pay 15 and climb two steps to reach the top. The total cost is 15.

Example 2:

1
2
Input: cost = [1,100,1,1,1,100,1,1,100,1]
Output: 6

Explanation: You will start at index 0.

  • Pay 1 and climb two steps to reach index 2.
  • Pay 1 and climb two steps to reach index 4.
  • Pay 1 and climb two steps to reach index 6.
  • Pay 1 and climb one step to reach index 7.
  • Pay 1 and climb two steps to reach index 9.
  • Pay 1 and climb one step to reach the top. The total cost is 6.

Constraints:

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

Question here and solution here

Solution

concept

If we solving from left to right:

dp[i] = minimum cost to reach step i (where i runs 0..n and n means the top).
You can start at step 0 or 1 for free → so dp[0]=dp[1]=0.
To reach i you must come from i-1 (one step) or i-2 (two steps). If you come from i-1 you must have paid cost[i-1]; if from i-2 you paid cost[i-2]

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

and we get dp[n] as the answer.

if we solving from right to left:

dp[i] = minimum cost from step i to reach the top (where i runs 0..n and n means the top).

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
class Solution:
	"""
	brute force
	"""
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        
        def dfs(i):
            if i >= len(cost):
                return 0
            return cost[i] + min(dfs(i + 1), dfs(i + 2))
        
        return min(dfs(0), dfs(1))
        
class Solution:
	"""
	top down (memozation)
	"""
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        dp = [-1] * len(cost)

        def dfs(i):
            if i >= len(cost):
                return 0
            if dp[i] != -1:
                return dp[i]

            dp[i] = cost[i] + min(dfs(i + 1), dfs(i + 2))
            return dp[i]
        
        return min(dfs(0), dfs(1))
        
class Solution:
	"""
	bottom up
	solving from left -> right
	"""
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n = len(cost)
        dp = [0] * (n + 1)

        for i in range(2, n + 1):
            dp[i] = min(dp[i - 1] + cost[i - 1],
                        dp[i - 2] + cost[i - 2])

        return dp[n]
        
class Solution:
	"""
	bottom up
	solving from right -> left
	"""
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n = len(cost)
        dp = [0] * (n + 1)
        # the last index is the goal (i.e. we added one extra 0, from the above line)
        # the 2nd last index is the cost of the final step, since this is fixed, we have to pay this cost to reach from n - 1 to n
        # after that we can dp from left to right
        dp[-2] = cost[-1]

        for i in range(n-2, -1, -1):
            dp[i] = min(cost[i] + dp[i+1], cost[i]+dp[i+2])
		# choose from step 0 or step 1, whichever is the minimum
        return min(dp[0], dp[1])
        
class Solution:
	"""
	bottom up
	solving from right -> left
	space optimised
	"""
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        cost.append(0) # [10, 15, 20] 0 -> add one 0 at the end, this is the goal

        for i in range(len(cost) - 3, -1, -1): # start from 3rd last, i,e, 15, and don't touch [20, 0]
            cost[i] = min(cost[i]+cost[i+1], cost[i]+cost[i+2])

        return min(cost[0], cost[1])

Complexity

time: $O(n)$
space: $O(n)$

This post is licensed under CC BY 4.0 by the author.