Given an integer array height[] where height[i] represents the height of the i-th stair, a frog starts from the first stair and wants to reach the last stair.
From any stair i, the frog has two options: it can either jump to the (i+1)th stair or the (i+2)th stair. The cost of a jump is the absolute difference in height between the two stairs.
Determine the minimum total cost required for the frog to reach the last stair.
Examples:
Input: heights[] = [20, 30, 40, 20]
Output: 20
Explanation: Minimum cost is incurred when the frog jumps from stair 0 to 1 then 1 to 3:
jump from stair 0 to 1: cost = |30 - 20| = 10
jump from stair 1 to 3: cost = |20 - 30| = 10
Total Cost = 10 + 10 = 20Input: heights[] = [30, 20, 50, 10, 40]
Output: 30
Explanation: Minimum cost will be incurred when frog jumps from stair 0 to 2 then 2 to 4:
jump from stair 0 to 2: cost = |50 - 30| = 20
jump from stair 2 to 4: cost = |40 - 50| = 10
Total Cost = 20 + 10 = 30
This problem is mainly a variation of finding n-th Fibonacci Number. Here we have costs also associated with the two previous numbers.
Table of Content
[Naive Approach] Recursion â O(2 ^ n) Time and O(n) Space
In this approach, we observe that to reach the nth stair, one can come either from the (nâ1)th or (nâ2)th stair.
So, in order to compute the minimum cost to reach the nth stair, we must know the minimum cost to reach the (nâ1)th and (nâ2)th stairs.
Similarly, in order to compute the minimum cost to reach the (n-1)th stair, we must know the minimum cost to reach the (nâ2)th and (nâ3)th stairs. This way we can observe that this can be done using recursion.
#include <iostream>
#include <vector>
using namespace std;
int minCostRec(int n, vector<int> &height)
{
// If there is only one
// stair(0-based index)
if (n == 0)
return 0;
// If there are only 2 stairs(0-based
// index), then frog can only take
// jump of size one
if (n == 1)
return abs(height[n] - height[n - 1]);
return min(minCostRec(n - 1, height) + abs(height[n] - height[n - 1]),
minCostRec(n - 2, height) + abs(height[n] - height[n - 2]));
}
int minCost(vector<int> &height)
{
int n = height.size();
return minCostRec(n - 1, height);
}
int main()
{
vector<int> height = {20, 30, 40, 20};
cout << minCost(height);
}
#include <stdio.h>
#include <stdlib.h>
int minCostRec(int n, int height[])
{
// If there is only one
// stair(0-based index)
if (n == 0)
return 0;
// If there are only 2 stairs(0-based
// index), then frog can only take
// jump of size one
if (n == 1)
return abs(height[n] - height[n - 1]);
return min(minCostRec(n - 1, height) + abs(height[n] - height[n - 1]),
minCostRec(n - 2, height) + abs(height[n] - height[n - 2]));
}
int minCost(int height[], int n)
{
return minCostRec(n - 1, height);
}
int min(int a, int b)
{
return (a < b) ? a : b;
}
int main()
{
int height[] = {20, 30, 40, 20};
int n = sizeof(height) / sizeof(height[0]);
printf("%d\n", minCost(height, n));
}
public class GFG {
// Function to find the minimum cost path
static int minCostRec(int n, int[] height)
{
// If there is only one stair
if (n == 0)
return 0;
// If there are only two stairs
if (n == 1)
return Math.abs(height[n] - height[n - 1]);
return Math.min(
minCostRec(n - 1, height)
+ Math.abs(height[n] - height[n - 1]),
minCostRec(n - 2, height)
+ Math.abs(height[n] - height[n - 2]));
}
// Function to find the minimum cost
static int minCost(int[] height)
{
int n = height.length;
return minCostRec(n - 1, height);
}
public static void main(String[] args)
{
int[] height = { 20, 30, 40, 20 };
System.out.println(minCost(height));
}
}
def minCostRec(n, height):
# If there is only one
# stair(0-based index)
if n == 0:
return 0
# If there are only 2 stairs(0-based
# index), then frog can only take
# jump of size one
if n == 1:
return abs(height[n] - height[n - 1])
return min(
minCostRec(n - 1, height) + abs(height[n] - height[n - 1]),
minCostRec(n - 2, height) + abs(height[n] - height[n - 2])
)
def minCost(height):
n = len(height)
return minCostRec(n - 1, height)
if __name__ == "__main__":
height = [20, 30, 40, 20]
print(minCost(height))
using System;
public class GFG {
// Function to find the minimum cost path
static int minCostRec(int n, int[] height)
{
// If there is only one stair
if (n == 0)
return 0;
// If there are only two stairs
if (n == 1)
return Math.Abs(height[n] - height[n - 1]);
return Math.Min(
minCostRec(n - 1, height)
+ Math.Abs(height[n] - height[n - 1]),
minCostRec(n - 2, height)
+ Math.Abs(height[n] - height[n - 2]));
}
// Function to find the minimum cost
static int minCost(int[] height)
{
int n = height.Length;
return minCostRec(n - 1, height);
}
public static void Main()
{
int[] height = { 20, 30, 40, 20 };
Console.WriteLine(minCost(height));
}
}
function minCostRec(n, height)
{
// If there is only one
// stair(0-based index)
if (n === 0)
return 0;
// If there are only 2 stairs(0-based
// index), then frog can only take
// jump of size one
if (n === 1)
return Math.abs(height[n] - height[n - 1]);
return Math.min(
minCostRec(n - 1, height)
+ Math.abs(height[n] - height[n - 1]),
minCostRec(n - 2, height)
+ Math.abs(height[n] - height[n - 2]));
}
function minCost(height)
{
let n = height.length;
return minCostRec(n - 1, height);
}
let height = [ 20, 30, 40, 20 ];
console.log(minCost(height));
Output
20
[Better Approach - 1] Memoization â O(n) Time and O(n) Space
In this approach, we use memoization to avoid recalculating the same subproblems multiple times.
For example, minCost(n) calls minCost(n-1) and minCost(n-2), while minCost(n-1) also calls minCost(n-2). Thus, minCost(n-2) is computed more than once.
To avoid this, we store the results of solved subproblems in a dp array and reuse them whenever needed, reducing redundant computations.
#include <iostream>
#include <vector>
using namespace std;
int minCostRec(int n, vector<int> &height, vector<int> &dp)
{
// If there is only one
// stair(0-based index)
if (n == 0)
return 0;
// If there are only 2 stairs(0-based
// index), then frog can only take
// jump of size one
if (n == 1)
return abs(height[n] - height[n - 1]);
// if the result for this subproblem is
// already computed then return it
if (dp[n] != -1)
return dp[n];
dp[n] = min(minCostRec(n - 1, height, dp) + abs(height[n] - height[n - 1]),
minCostRec(n - 2, height, dp) + abs(height[n] - height[n - 2]));
return dp[n];
}
int minCost(vector<int> &height)
{
int n = height.size();
// filling dp array with invalid values
vector<int> dp(n + 1, -1);
return minCostRec(n - 1, height, dp);
}
int main()
{
vector<int> height = {20, 30, 40, 20};
cout << minCost(height);
}
#include <stdio.h>
#include <stdlib.h>
int minCostRec(int n, int height[], int dp[])
{
// If there is only one
// stair(0-based index)
if (n == 0)
return 0;
// If there are only 2 stairs(0-based
// index), then frog can only take
// jump of size one
if (n == 1)
return abs(height[n] - height[n - 1]);
// if the result for this subproblem is
// already computed then return it
if (dp[n] != -1)
return dp[n];
int cost1 = minCostRec(n - 1, height, dp) + abs(height[n] - height[n - 1]);
int cost2 = minCostRec(n - 2, height, dp) + abs(height[n] - height[n - 2]);
dp[n] = (cost1 < cost2) ? cost1 : cost2;
return dp[n];
}
int minCost(int height[], int n)
{
int *dp = (int *)malloc((n + 1) * sizeof(int));
// filling dp array with invalid values
for (int i = 0; i <= n; i++)
dp[i] = -1;
int res = minCostRec(n - 1, height, dp);
free(dp);
return res;
}
int main()
{
int height[] = {20, 30, 40, 20};
int n = sizeof(height) / sizeof(height[0]);
printf("%d\n", minCost(height, n));
}
import java.util.Arrays;
public class GFG {
// Function to find the minimum cost path
static int minCostRec(int n, int[] height, int[] dp)
{
// If there is only one stair
if (n == 0)
return 0;
// If there are only two stairs
if (n == 1)
return Math.abs(height[n] - height[n - 1]);
// Return the stored result if already computed
if (dp[n] != -1)
return dp[n];
// Calculate and store the minimum cost
dp[n] = Math.min(
minCostRec(n - 1, height, dp)
+ Math.abs(height[n] - height[n - 1]),
minCostRec(n - 2, height, dp)
+ Math.abs(height[n] - height[n - 2]));
return dp[n];
}
// Function to find the minimum cost
static int minCost(int[] height)
{
int n = height.length;
int[] dp = new int[n];
Arrays.fill(dp, -1);
return minCostRec(n - 1, height, dp);
}
public static void main(String[] args)
{
int[] height = { 20, 30, 40, 20 };
System.out.println(minCost(height));
}
}
def minCostRec(n, height, dp):
# If there is only one
# stair(0-based index)
if n == 0:
return 0
# If there are only 2 stairs(0-based
# index), then frog can only take
# jump of size one
if n == 1:
return abs(height[n] - height[n - 1])
# if the result for this subproblem is
# already computed then return it
if dp[n] != -1:
return dp[n]
dp[n] = min(
minCostRec(n - 1, height, dp) + abs(height[n] - height[n - 1]),
minCostRec(n - 2, height, dp) + abs(height[n] - height[n - 2])
)
return dp[n]
def minCost(height):
n = len(height)
# filling dp array with invalid values
dp = [-1] * (n + 1)
return minCostRec(n - 1, height, dp)
if __name__ == "__main__":
height = [20, 30, 40, 20]
print(minCost(height))
using System;
class GFG {
// Function to find the minimum cost path
static int minCostRec(int n, int[] height, int[] dp)
{
// If there is only one stair
if (n == 0)
return 0;
// If there are only two stairs
if (n == 1)
return Math.Abs(height[n] - height[n - 1]);
// Return the stored result if already computed
if (dp[n] != -1)
return dp[n];
// Calculate and store the minimum cost
dp[n] = Math.Min(
minCostRec(n - 1, height, dp)
+ Math.Abs(height[n] - height[n - 1]),
minCostRec(n - 2, height, dp)
+ Math.Abs(height[n] - height[n - 2]));
return dp[n];
}
// Function to find the minimum cost
static int minCost(int[] height)
{
int n = height.Length;
int[] dp = new int[n];
Array.Fill(dp, -1);
return minCostRec(n - 1, height, dp);
}
public static void Main()
{
int[] height = { 20, 30, 40, 20 };
Console.WriteLine(minCost(height));
}
}
function minCostRec(n, height, dp)
{
// If there is only one
// stair(0-based index)
if (n === 0)
return 0;
// If there are only 2 stairs(0-based
// index), then frog can only take
// jump of size one
if (n === 1)
return Math.abs(height[n] - height[n - 1]);
// if the result for this subproblem is
// already computed then return it
if (dp[n] !== -1)
return dp[n];
dp[n] = Math.min(
minCostRec(n - 1, height, dp)
+ Math.abs(height[n] - height[n - 1]),
minCostRec(n - 2, height, dp)
+ Math.abs(height[n] - height[n - 2]));
return dp[n];
}
function minCost(height)
{
const n = height.length;
// filling dp array with invalid values
const dp = new Array(n + 1).fill(-1);
return minCostRec(n - 1, height, dp);
}
const height = [ 20, 30, 40, 20 ];
console.log(minCost(height));
Output
20
[Better Approach - 2] Bottom-Up DP (Tabulation) â O(n) Time and O(n) Space
In this approach, we use tabulation (bottom-up dynamic programming) to solve the problem iteratively, starting from the smallest subproblems.
We store the minimum cost to reach each stair in a dp array. For every stair, we calculate the minimum cost using the results of the previous two stairs and store it for future calculations.
This avoids repeated computations and improves the time complexity to O(n), with O(n) auxiliary space for the DP array.
#include <iostream>
#include <vector>
using namespace std;
int minCost(vector<int> &height)
{
int n = height.size();
// DP array to store the minimum cost
vector<int> dp(n);
// If there is only one stair,
// cost will be zero
dp[0] = 0;
// If there are 2 stairs, then frog
// can only take jump of size one
if (n > 1)
dp[1] = abs(height[1] - height[0]);
for (int i = 2; i < n; i++)
{
dp[i] = min(dp[i - 1] + abs(height[i] - height[i - 1]), dp[i - 2] + abs(height[i] - height[i - 2]));
}
return dp[n - 1];
}
int main()
{
vector<int> height = {20, 30, 40, 20};
cout << minCost(height);
}
#include <stdio.h>
#include <stdlib.h>
int min(int a, int b)
{
return (a < b) ? a : b;
}
int minCost(int height[], int n)
{
// DP array to store the minimum cost
int *dp = (int *)malloc(n * sizeof(int));
// If there is only one stair,
// cost will be zero
dp[0] = 0;
// If there are 2 stairs, then frog
// can only take jump of size one
if (n > 1)
dp[1] = abs(height[1] - height[0]);
for (int i = 2; i < n; i++)
{
dp[i] = min(dp[i - 1] + abs(height[i] - height[i - 1]), dp[i - 2] + abs(height[i] - height[i - 2]));
}
int result = dp[n - 1];
free(dp);
return result;
}
int main()
{
int height[] = {20, 30, 40, 20};
int n = sizeof(height) / sizeof(height[0]);
printf("%d\n", minCost(height, n));
}
class GFG {
// Function to find the minimum cost path
static int minCost(int[] height)
{
int n = height.length;
// DP array to store the minimum cost
// to reach each stair
int[] dp = new int[n];
// Cost to reach the first stair is zero
dp[0] = 0;
// Cost to reach the second stair
if (n > 1)
dp[1] = Math.abs(height[1] - height[0]);
// Calculate the minimum cost for each stair
for (int i = 2; i < n; i++) {
dp[i] = Math.min(
dp[i - 1]
+ Math.abs(height[i] - height[i - 1]),
dp[i - 2]
+ Math.abs(height[i] - height[i - 2]));
}
// Return the minimum cost to reach the last stair
return dp[n - 1];
}
public static void main(String[] args)
{
int[] height = { 20, 30, 40, 20 };
System.out.println(minCost(height));
}
}
def minCost(height):
n = len(height)
# DP array to store the minimum cost
dp = [0] * n
# If there is only one stair,
# cost will be zero
dp[0] = 0
# If there are 2 stairs, then frog
# can only take jump of size one
if n > 1:
dp[1] = abs(height[1] - height[0])
for i in range(2, n):
dp[i] = min(dp[i - 1] + abs(height[i] - height[i - 1]),
dp[i - 2] + abs(height[i] - height[i - 2]))
return dp[n - 1]
if __name__ == "__main__":
height = [20, 30, 40, 20]
print(minCost(height))
using System;
class GFG {
// Function to find the minimum cost path
static int minCost(int[] height)
{
int n = height.Length;
// DP array to store the minimum cost
// to reach each stair
int[] dp = new int[n];
// Cost to reach the first stair is zero
dp[0] = 0;
// Cost to reach the second stair
if (n > 1)
dp[1] = Math.Abs(height[1] - height[0]);
// Calculate the minimum cost for each stair
for (int i = 2; i < n; i++) {
dp[i] = Math.Min(
dp[i - 1]
+ Math.Abs(height[i] - height[i - 1]),
dp[i - 2]
+ Math.Abs(height[i] - height[i - 2]));
}
// Return the minimum cost to reach the last stair
return dp[n - 1];
}
public static void Main()
{
int[] height = { 20, 30, 40, 20 };
Console.WriteLine(minCost(height));
}
}
function minCost(height)
{
const n = height.length;
// DP array to store the minimum cost
const dp = new Array(n);
// If there is only one stair,
// cost will be zero
dp[0] = 0;
// If there are 2 stairs, then frog
// can only take jump of size one
if (n > 1)
dp[1] = Math.abs(height[1] - height[0]);
for (let i = 2; i < n; i++) {
dp[i] = Math.min(
dp[i - 1] + Math.abs(height[i] - height[i - 1]),
dp[i - 2]
+ Math.abs(height[i] - height[i - 2]));
}
return dp[n - 1];
}
const height = [ 20, 30, 40, 20 ];
console.log(minCost(height));
Output
20
[Expected Approach] Space Optimized DP â O(n) Time and O(1) Space
In this approach, we observe that in order to find solution for a particular state, we only need the answer for just two previous states.
Hence, we can store the results for the previous two states, and as we move forward, we keep updating them to compute the next values.
This means keeping track of the last two states and using them to calculate the next one will help us to find the solution optimally, without using extra space.
#include <iostream>
#include <vector>
using namespace std;
int minCost(vector<int> &height)
{
int n = height.size();
if (n == 1)
return 0;
// Variables prev1 and prev2 to store the result
// of last and second last states
int prev2 = 0;
int prev1 = abs(height[1] - height[0]);
for (int i = 2; i < n; i++)
{
int curr = min(prev1 + abs(height[i] - height[i - 1]), prev2 + abs(height[i] - height[i - 2]));
// Updating prev2 to previous result and
// prev1 to current result
prev2 = prev1;
prev1 = curr;
}
// In the last iteration, final value
// of curr is stored in prev1
return prev1;
}
int main()
{
vector<int> height = {20, 30, 40, 20};
cout << minCost(height);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int minCost(int height[], int n)
{
if (n == 1)
return 0;
// Variables prev1 and prev2 to store the result
// of last and second last states
int prev2 = 0;
int prev1 = abs(height[1] - height[0]);
for (int i = 2; i < n; i++)
{
int curr = (prev1 + abs(height[i] - height[i - 1]) < prev2 + abs(height[i] - height[i - 2]))
? (prev1 + abs(height[i] - height[i - 1]))
: (prev2 + abs(height[i] - height[i - 2]));
// Updating prev2 to previous result and
// prev1 to current result
prev2 = prev1;
prev1 = curr;
}
// In the last iteration, final value
// of curr is stored in prev1
return prev1;
}
int main()
{
int height[] = {20, 30, 40, 20};
int n = sizeof(height) / sizeof(height[0]);
printf("%d", minCost(height, n));
return 0;
}
class GFG {
// Function to find the minimum cost path
static int minCost(int[] height)
{
int n = height.length;
// If there is only one stair
if (n == 1)
return 0;
// Store the costs of the previous two stairs
int prev2 = 0;
int prev1 = Math.abs(height[1] - height[0]);
// Calculate the minimum cost for each stair
for (int i = 2; i < n; i++) {
int curr = Math.min(
prev1 + Math.abs(height[i] - height[i - 1]),
prev2
+ Math.abs(height[i] - height[i - 2]));
// Update the previous two states
prev2 = prev1;
prev1 = curr;
}
// Return the minimum cost to reach the last stair
return prev1;
}
public static void main(String[] args)
{
int[] height = { 20, 30, 40, 20 };
System.out.println(minCost(height));
}
}
def minCost(height):
n = len(height)
if n == 1:
return 0
# Variables prev1 and prev2 to store the result
# of last and second last states
prev2 = 0
prev1 = abs(height[1] - height[0])
for i in range(2, n):
curr = min(prev1 + abs(height[i] - height[i - 1]),
prev2 + abs(height[i] - height[i - 2]))
# Updating prev2 to previous result and
# prev1 to current result
prev2 = prev1
prev1 = curr
# In the last iteration, final value
# of curr is stored in prev1
return prev1
if __name__ == "__main__":
height = [20, 30, 40, 20]
print(minCost(height))
using System;
class GFG {
// Function to find the minimum cost path
static int minCost(int[] height)
{
int n = height.Length;
// If there is only one stair
if (n == 1)
return 0;
// Store the costs of the previous two stairs
int prev2 = 0;
int prev1 = Math.Abs(height[1] - height[0]);
// Calculate the minimum cost for each stair
for (int i = 2; i < n; i++) {
int curr = Math.Min(
prev1 + Math.Abs(height[i] - height[i - 1]),
prev2
+ Math.Abs(height[i] - height[i - 2]));
// Update the previous two states
prev2 = prev1;
prev1 = curr;
}
// Return the minimum cost to reach the last stair
return prev1;
}
static void Main()
{
int[] height = { 20, 30, 40, 20 };
Console.WriteLine(minCost(height));
}
}
function minCost(height)
{
const n = height.length;
if (n === 1)
return 0;
// Variables prev1 and prev2 to store the result
// of last and second last states
let prev2 = 0;
let prev1 = Math.abs(height[1] - height[0]);
for (let i = 2; i < n; i++) {
let curr = Math.min(
prev1 + Math.abs(height[i] - height[i - 1]),
prev2 + Math.abs(height[i] - height[i - 2]));
// Updating prev2 to previous result and
// prev1 to current result
prev2 = prev1;
prev1 = curr;
}
// In the last iteration, final value
// of curr is stored in prev1
return prev1;
}
const height = [ 20, 30, 40, 20 ];
console.log(minCost(height));
Output
20