Minimum Cost to Reach the Top (original) (raw)
Given an array of integers **cost[] of length **n, where **cost[i] is the cost of the i th step on a staircase. Once the cost is paid, we can either climb **one or two steps.
We can either start from the step with **index 0, or the step with **index 1. The task is to find the minimum cost to reach the **top.
**Examples:
**Input: cost[] = [10, 15, 20]
**Output: 15
**Explanation: The cheapest option is to start from step with index 1, pay cost[1] and go to the top.
**Input: cost[] = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
**Output: 6
**Explanation: The cheapest option is to start from step with index 1on cost[0], and only step on 1s, skipping cost[3].
Table of Content
- [Naive Approach] Using Recursion - O(2^n) Time and O(n) Space
- [Better Approach 1] Using Top-Down DP (Memoization) – O(n) Time and O(n) Space
- [Better Approach 2] Using Bottom-Up DP (Tabulation) - O(n) Time and O(n) Space
- [Expected Approach] Using Space Optimized DP – O(n) Time and O(1) Space
[Naive Approach] Using Recursion - O(2^n) Time and O(n) Space
This problem is an extension of problem: Climbing Stairs to reach at the top.
There are n stairs, and a person is allowed to climb 1 or 2 stairs. If a person is standing at **i-th stair, the person can move to **i+1, i+2, stair. A **recursive function can be formed where at current **index i the function is **recursively called for **i+1, i+2 th stair.
There is another way of forming the recursive function. To reach a **stair i, a person has to jump either from i-1, or i-2 th stair.
- **minCost(n) = cost[i] + min(minCost(n-1) , minCost(n-2))
C++ `
// C++ program to count number of // ways to reach nth stair. #include <bits/stdc++.h> using namespace std;
int minCostRecur(int i, vector &cost) {
// Base case
if (i==0 || i==1) {
return cost[i];
}
return cost[i] + min(minCostRecur(i-1, cost),
minCostRecur(i-2, cost));}
int minCostClimbingStairs(vector &cost) { int n = cost.size();
if (n==1) return cost[0];
// Return minimum of cost to
// reach (n-1)th stair and
// cost to reach (n-2)th stair
return min(minCostRecur(n-1, cost),
minCostRecur(n-2, cost));}
int main() { vector cost = { 16, 19, 10, 12, 18 }; cout << minCostClimbingStairs(cost) << endl; return 0; }
Java
// Java program to count number of // ways to reach nth stair. import java.util.*;
class GfG {
static int minCostRecur(int i, int[] cost) {
// Base case
if (i == 0 || i == 1) {
return cost[i];
}
return cost[i] + Math.min(minCostRecur(i - 1, cost),
minCostRecur(i - 2, cost));
}
static int minCostClimbingStairs(int[] cost) {
int n = cost.length;
if (n == 1) return cost[0];
// Return minimum of cost to
// reach (n-1)th stair and
// cost to reach (n-2)th stair
return Math.min(minCostRecur(n - 1, cost),
minCostRecur(n - 2, cost));
}
public static void main(String[] args) {
int[] cost = { 16, 19, 10, 12, 18 };
System.out.println(minCostClimbingStairs(cost));
}}
Python
Python program to count number of
ways to reach nth stair.
def minCostRecur(i, cost):
# Base case
if i == 0 or i == 1:
return cost[i]
return cost[i] + min(minCostRecur(i - 1, cost),
minCostRecur(i - 2, cost))def minCostClimbingStairs(cost): n = len(cost)
if n == 1:
return cost[0]
# Return minimum of cost to
# reach (n-1)th stair and
# cost to reach (n-2)th stair
return min(minCostRecur(n - 1, cost),
minCostRecur(n - 2, cost))if name == "main": cost = [16, 19, 10, 12, 18] print(minCostClimbingStairs(cost))
C#
// C# program to count number of // ways to reach nth stair.
using System;
class GfG {
static int minCostRecur(int i, int[] cost) {
// Base case
if (i == 0 || i == 1) {
return cost[i];
}
return cost[i] + Math.Min(minCostRecur(i - 1, cost),
minCostRecur(i - 2, cost));
}
static int minCostClimbingStairs(int[] cost) {
int n = cost.Length;
if (n == 1) return cost[0];
// Return minimum of cost to reach (n-1)th
// stair and cost to reach (n-2)th stair
return Math.Min(minCostRecur(n - 1, cost),
minCostRecur(n - 2, cost));
}
static void Main(string[] args) {
int[] cost = { 16, 19, 10, 12, 18 };
Console.WriteLine(minCostClimbingStairs(cost));
}}
JavaScript
// JavaScript program to count number of // ways to reach nth stair. function minCostRecur(i, cost) {
// Base case
if (i === 0 || i === 1) {
return cost[i];
}
return cost[i] + Math.min(minCostRecur(i - 1, cost),
minCostRecur(i - 2, cost));}
function minCostClimbingStairs(cost) { let n = cost.length;
if (n === 1) return cost[0];
// Return minimum of cost to reach (n-1)th stair and
// cost to reach (n-2)th stair
return Math.min(minCostRecur(n - 1, cost),
minCostRecur(n - 2, cost));}
// Driver Code let cost = [16, 19, 10, 12, 18]; console.log(minCostClimbingStairs(cost));
`
[Better Approach 1] Using Top-Down DP (Memoization) – O(n) Time and O(n) Space
If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming:
**1. Optimal Substructure: Minimum cost to reach the nth stair, i.e., **minCost(n), depends on the optimal solutions of the subproblems **minCost(n-1) , and **minCost(n-2). By choosing the **minimum of these optimal substructures, we can efficiently calculate the minimum cost to reach the nth stair.
**2. Overlapping Subproblems: While applying a **recursive approach in this problem, we notice that certain subproblems are computed **multiple times. For example, when calculating minCost(4), we recursively calculate **minCost(3) and **minCost(2) which in turn will **recursively compute **minCost(2) again. This redundancy leads to overlapping subproblems.
- There is only **one parameter that changes in the recursive solution and it can go from **0 to n. So we create a 1D array of size n+1 for memoization.
- We initialize this **array as -1 to indicate nothing is computed initially.
- Now we modify our recursive solution to first check if the value is -1, then only make recursive calls. This way, we avoid re-computations of the same subproblems. C++ `
// C++ program to count number of // ways to reach nth stair. #include <bits/stdc++.h> using namespace std;
int minCostRecur(int i, vector &cost, vector &memo) {
// Base case
if (i==0 || i==1) {
return cost[i];
}
// If value is memoized
if (memo[i]!=-1) return memo[i];
return memo[i] = cost[i] +
min(minCostRecur(i-1, cost, memo),
minCostRecur(i-2, cost, memo));}
int minCostClimbingStairs(vector &cost) { int n = cost.size();
if (n==1) return cost[0];
vector<int> memo(n, -1);
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return min(minCostRecur(n-1, cost, memo),
minCostRecur(n-2, cost, memo));}
int main() { vector cost = { 16, 19, 10, 12, 18 }; cout << minCostClimbingStairs(cost) << endl; return 0; }
Java
// Java program to count number of // ways to reach nth stair. import java.util.*;
class GfG {
static int minCostRecur(int i, int[] cost, int[] memo) {
// Base case
if (i == 0 || i == 1) {
return cost[i];
}
// If value is memoized
if (memo[i] != -1) return memo[i];
return memo[i] = cost[i] +
Math.min(minCostRecur(i - 1, cost, memo),
minCostRecur(i - 2, cost, memo));
}
static int minCostClimbingStairs(int[] cost) {
int n = cost.length;
if (n == 1) return cost[0];
int[] memo = new int[n];
Arrays.fill(memo, -1);
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return Math.min(minCostRecur(n - 1, cost, memo),
minCostRecur(n - 2, cost, memo));
}
public static void main(String[] args) {
int[] cost = { 16, 19, 10, 12, 18 };
System.out.println(minCostClimbingStairs(cost));
}}
Python
Python program to count number of
ways to reach nth stair.
def minCostRecur(i, cost, memo):
# Base case
if i == 0 or i == 1:
return cost[i]
# If value is memoized
if memo[i] != -1:
return memo[i]
memo[i] = cost[i] + min(minCostRecur(i - 1, cost, memo),
minCostRecur(i - 2, cost, memo))
return memo[i]def minCostClimbingStairs(cost): n = len(cost)
if n == 1:
return cost[0]
memo = [-1] * n
# Return minimum of cost to
# climb (n-1)th stair and
# cost to reach (n-2)th stair
return min(minCostRecur(n - 1, cost, memo),
minCostRecur(n - 2, cost, memo))if name == "main": cost = [16, 19, 10, 12, 18] print(minCostClimbingStairs(cost))
C#
// C# program to count number of // ways to reach nth stair. using System;
class GfG {
static int minCostRecur(int i, int[] cost, int[] memo) {
// Base case
if (i == 0 || i == 1) {
return cost[i];
}
// If value is memoized
if (memo[i] != -1) return memo[i];
return memo[i] = cost[i] +
Math.Min(minCostRecur(i - 1, cost, memo),
minCostRecur(i - 2, cost, memo));
}
static int minCostClimbingStairs(int[] cost) {
int n = cost.Length;
if (n == 1) return cost[0];
int[] memo = new int[n];
for (int i = 0; i < n; i++) memo[i] = -1;
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return Math.Min(minCostRecur(n - 1, cost, memo),
minCostRecur(n - 2, cost, memo));
}
static void Main(string[] args) {
int[] cost = { 16, 19, 10, 12, 18 };
Console.WriteLine(minCostClimbingStairs(cost));
}}
JavaScript
// JavaScript program to count number of // ways to reach nth stair.
function minCostRecur(i, cost, memo) {
// Base case
if (i === 0 || i === 1) {
return cost[i];
}
// If value is memoized
if (memo[i] !== -1) return memo[i];
memo[i] = cost[i] + Math.min(minCostRecur(i - 1, cost, memo),
minCostRecur(i - 2, cost, memo));
return memo[i];}
function minCostClimbingStairs(cost) { let n = cost.length;
if (n === 1) return cost[0];
let memo = new Array(n).fill(-1);
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return Math.min(minCostRecur(n - 1, cost, memo),
minCostRecur(n - 2, cost, memo));}
let cost = [16, 19, 10, 12, 18]; console.log(minCostClimbingStairs(cost));
`
[Better Approach 2] Using Bottom-Up DP (Tabulation) - O(n) Time and O(n) Space
_The idea is to create a**1-D **array, _fill values for first **t**wo stairs _and compute the values from 2 to n _using the previous **two _results. For i = 2 to n, do **dp[i] = cost[i] + min(dp[i-1] + dp[i-2]).
**Illustration:
C++ `
// C++ program to count number of // ways to reach nth stair. #include <bits/stdc++.h> using namespace std;
int minCostClimbingStairs(vector &cost) { int n = cost.size();
if (n==1) return cost[0];
vector<int> dp(n);
dp[0] = cost[0];
dp[1] = cost[1];
for (int i=2; i<n; i++) {
dp[i] = cost[i] + min(dp[i-1], dp[i-2]);
}
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return min(dp[n-1], dp[n-2]);}
int main() { vector cost = { 16, 19, 10, 12, 18 }; cout << minCostClimbingStairs(cost) << endl; return 0; }
Java
// Java program to count number of // ways to reach nth stair. import java.util.*;
class GfG {
static int minCostClimbingStairs(int[] cost) {
int n = cost.length;
if (n == 1) return cost[0];
int[] dp = new int[n];
dp[0] = cost[0];
dp[1] = cost[1];
for (int i = 2; i < n; i++) {
dp[i] = cost[i] + Math.min(dp[i - 1], dp[i - 2]);
}
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return Math.min(dp[n - 1], dp[n - 2]);
}
public static void main(String[] args) {
int[] cost = { 16, 19, 10, 12, 18 };
System.out.println(minCostClimbingStairs(cost));
}}
Python
Python program to count number of
ways to reach nth stair.
def minCostClimbingStairs(cost): n = len(cost)
if n == 1:
return cost[0]
dp = [0] * n
dp[0] = cost[0]
dp[1] = cost[1]
for i in range(2, n):
dp[i] = cost[i] + min(dp[i - 1], dp[i - 2])
# Return minimum of cost to
# climb (n-1)th stair and
# cost to reach (n-2)th stair
return min(dp[n - 1], dp[n - 2])if name == "main": cost = [16, 19, 10, 12, 18] print(minCostClimbingStairs(cost))
C#
// C# program to count number of // ways to reach nth stair.
using System;
class GfG {
static int minCostClimbingStairs(int[] cost) {
int n = cost.Length;
if (n == 1) return cost[0];
int[] dp = new int[n];
dp[0] = cost[0];
dp[1] = cost[1];
for (int i = 2; i < n; i++) {
dp[i] = cost[i] + Math.Min(dp[i - 1], dp[i - 2]);
}
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return Math.Min(dp[n - 1], dp[n - 2]);
}
static void Main(string[] args) {
int[] cost = { 16, 19, 10, 12, 18 };
Console.WriteLine(minCostClimbingStairs(cost));
}}
JavaScript
// JavaScript program to count number of // ways to reach nth stair.
function minCostClimbingStairs(cost) { let n = cost.length;
if (n === 1) return cost[0];
let dp = new Array(n);
dp[0] = cost[0];
dp[1] = cost[1];
for (let i = 2; i < n; i++) {
dp[i] = cost[i] + Math.min(dp[i - 1], dp[i - 2]);
}
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return Math.min(dp[n - 1], dp[n - 2]);}
let cost = [16, 19, 10, 12, 18]; console.log(minCostClimbingStairs(cost));
`
[Expected Approach] Using Space Optimized DP – O(n) Time and O(1) Space
_The idea is to store only the **previous _two computed values. We can observe that for a given stair, only the result of last two _stairs are needed. So only store these two values and update them after each step.
C++ `
// C++ program to count number of // ways to reach nth stair. #include <bits/stdc++.h> using namespace std;
int minCostClimbingStairs(vector &cost) { int n = cost.size();
if (n==1) return cost[0];
int prev2 = cost[0];
int prev1 = cost[1];
for (int i=2; i<n; i++) {
int curr = cost[i] +
min(prev1, prev2);
prev2 = prev1;
prev1 = curr;
}
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return min(prev1, prev2);}
int main() { vector cost = { 16, 19, 10, 12, 18 }; cout << minCostClimbingStairs(cost) << endl; return 0; }
Java
// Java program to count number of // ways to reach nth stair.
import java.util.*;
class GfG {
static int minCostClimbingStairs(int[] cost) {
int n = cost.length;
if (n == 1) return cost[0];
int prev2 = cost[0];
int prev1 = cost[1];
for (int i = 2; i < n; i++) {
int curr = cost[i] + Math.min(prev1, prev2);
prev2 = prev1;
prev1 = curr;
}
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return Math.min(prev1, prev2);
}
public static void main(String[] args) {
int[] cost = { 16, 19, 10, 12, 18 };
System.out.println(minCostClimbingStairs(cost));
}}
Python
Python program to count number of
ways to reach nth stair.
def minCostClimbingStairs(cost): n = len(cost)
if n == 1:
return cost[0]
prev2 = cost[0]
prev1 = cost[1]
for i in range(2, n):
curr = cost[i] + min(prev1, prev2)
prev2 = prev1
prev1 = curr
# Return minimum of cost to
# climb (n-1)th stair and
# cost to reach (n-2)th stair
return min(prev1, prev2)if name == "main": cost = [16, 19, 10, 12, 18] print(minCostClimbingStairs(cost))
C#
// C# program to count number of // ways to reach nth stair.
using System;
class GfG {
static int minCostClimbingStairs(int[] cost) {
int n = cost.Length;
if (n == 1) return cost[0];
int prev2 = cost[0];
int prev1 = cost[1];
for (int i = 2; i < n; i++) {
int curr = cost[i] + Math.Min(prev1, prev2);
prev2 = prev1;
prev1 = curr;
}
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return Math.Min(prev1, prev2);
}
static void Main(string[] args) {
int[] cost = { 16, 19, 10, 12, 18 };
Console.WriteLine(minCostClimbingStairs(cost));
}}
JavaScript
// JavaScript program to count number of // ways to reach nth stair. function minCostClimbingStairs(cost) { let n = cost.length;
if (n === 1) return cost[0];
let prev2 = cost[0];
let prev1 = cost[1];
for (let i = 2; i < n; i++) {
let curr = cost[i] + Math.min(prev1, prev2);
prev2 = prev1;
prev1 = curr;
}
// Return minimum of cost to
// climb (n-1)th stair and
// cost to reach (n-2)th stair
return Math.min(prev1, prev2);}
let cost = [16, 19, 10, 12, 18]; console.log(minCostClimbingStairs(cost));
`

