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.

Input: cost = [10,15,20]
Output: 15
Explanation: We can start at index 1 and pay 15, then climb two steps.
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.
So, the total cost is 6.
We will be taking this highlighted indexes path. [ 1 ,100, 1 ,1, 1 ,100, 1 , 1 , 100, 1 ]

Contents

In this approach, we will compute all possible outcomes recursively, first by stating at index 0 and take minimum cost to reach top of the floor, then start at index 1 and take minimum cost to reach top of the floor. Finally take minimum between these two outcomes.

public class MinCostClimbingStairs { static int bruteForceApproach(int[] cost) { // we can start from index 0 or 1, so taking minimum from both outcomes return Math.min(bruteForceApproachRec(cost, 0), bruteForceApproachRec(cost, 1)); } static int bruteForceApproachRec(int[] cost, int start) { if(start>=cost.length) { // base case, when we reach end of array or out of bounds // as we are calling recursively with start+1 and start+2 return 0; } return cost[start] + Math.min(bruteForceApproachRec(cost, start+1), bruteForceApproachRec(cost, start+2)); } }
Complexity Analysis:

Time complexity: Above code runs in O(2n) time where n is the length of cost input array, this is because we are creating a decision tree with two possibilities at each step.
Space complexity: O(n) as we are making recursive loops n times and this is the memory used by stack.

From the above brute force approach, we can notice that there are some overlapping problems.

For example, let's say cost = [4, 1, 8, 3]

import java.util.HashMap; public class MinCostClimbingStairs { static int dpMemoizationApproach(int[] cost) { // we can start from index 0 or 1, so taking minimum from both outcomes HashMap<Integer, Integer> cache = new HashMap<>(); return Math.min(bruteForceApproachRec(cost, 0), bruteForceApproachRec(cost, 1)); } static int dpMemoizationApproachRec(int[] cost, int start, HashMap<Integer, Integer> cache) { if(start>=cost.length) { // base case, when we reach end of array or out of bounds // as we are calling recursively with start+1 and start+2 return 0; } if(cache.containsKey(start)) { return cache.get(start); } int result = cost[start] + Math.min(bruteForceApproachRec(cost, start+1), bruteForceApproachRec(cost, start+2)); cache.put(start, result); return result; } }
Complexity Analysis:

Time complexity: Above code runs in O(n) time where n is the length of cost input array.
Space complexity: O(n) for the cache we are maintaining and stack for recursive calls.

In this approach we will look at solving the problem using Dynamic programming using tabulation caching mechanism.
The time and memory complexity will be same as above solution using memoization, but we can notice a pattern to improve memory complexity to constant in later solution.

Intution behind this solution is, when we are at ith step, possible ways to reach that step with minimum cost will be Min(cost at index i-1, cost at i-2), when we store the result back into cache, we will add cost at current index, so that it represents the cost to come to that index plus cost we should pay to take next step from here.

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

Base cases for this solution will be dp[0] = cost[0] and dp[1] = cost[1], this is because as the problem states we can either starts at index 0 or 1, if we start at 0th index, minimum cost will be cost[0], similarly if we start at 1st index, minimum cost will be cost[1].

Finally, take the minimum stored at last two indexes of the dp array, this will give us the minimum whether we start at index 0 or 1, and take either 1 or 2 steps from those last two indexes.

public class MinCostClimbingStairs { /* DP tabulation approach*/ static int dpTabulationApproach(int[] cost) { int[] dp = new int[cost.length]; dp[0] = cost[0]; dp[1] = cost[1]; for (int i =2; i<cost.length; i++){ dp[i] = cost[i] + Math.min(dp[i-1], dp[i-2]); } return Math.min(dp[cost.length-1], dp[cost.length-2]); } }
Complexity Analysis:

Time complexity: Above code runs in O(n) time where n is the length of cost input array.
Space complexity: O(n) since we have a dp array with size n.

If we look at above DP solution using tabulation, we can see that we just need previous two values only.
If we are at step i, to calculate minimum we only need minimum cost at i-1th step and i-2nd step.

public class MinCostClimbingStairs { /* DP tabulation approach memory optimized*/ static int dpTabulationApproachMemoryOptimized(int[] cost) { int prev = cost[0]; int current = cost[1]; for (int i =2; i<cost.length; i++){ int temp = cost[i] + Math.min(prev, current); prev = current; current = temp; } return Math.min(prev, current); } }
Complexity Analysis:

Time complexity: Above code runs in O(n) time where n is the length of cost input array.
Space complexity: O(1) since we are only using prev, current and a temp variables.

Above implementations source code can be found at GitHub link for Java code