Minimize the number of steps required to reach the end of the array
Given an integer array arr[] of length N consisting of positive integers, the task is to minimize the number of steps required to reach the index ‘N-1’. At a given step if we are at index ‘i’ we can go to index ‘i-arr[i]’ or ‘i+arr[i]’ given we have not visited those indexes before. Also, we cannot go outside the bounds of the array. Print -1 if there is not possible way.
Examples:
Input : arr[] = {1, 1, 1} Output : 2 The path will be 0 -> 1 -> 2. Step 1 - 0 to 1 Step 2 - 1 to 2 Input : {2, 1} Output : -1
This problem can be solved using dynamic programming approach.
Let’s discuss an approach that might seem correct at start. Let’s suppose we are at ith index. Can we directly say that dp[i] = 1 + min( dp[i-arr[i]], dp[i+arr[i]] ) ?
No, we cannot. The path we took to reach the index ‘i’ also matters as indexes we used before won’t be available to visit anymore.
Thus, the only approach we are left with is trying out all the possible combinations which can be really large. In this article, we will use bit-masking approach to reduce the complexity to exponential. Our mask will be an integer value with the following features.
1) If, a index 'i' is visited, ith bit will be set 1 in the mask. 2) Else that bit will be set 0.
The required recurrence relation will be.
dp[i][mask] = 1 + min(dp[i+arr[i]][mask|(1<<i)], dp[i-arr[i]][mask|(1<<i)])
Below is the implementation of the above approach:
CPP
// C++ implementation of the above approach #include <bits/stdc++.h> #define maxLen 10 #define maskLen 130 using namespace std; // variable to store states of dp int dp[maxLen][maskLen]; // variable to check if a given state // has been solved bool v[maxLen][maskLen]; // Function to find the minimum number of steps // required to reach the end of the array int minSteps( int arr[], int i, int mask, int n) { // base case if (i == n - 1) return 0; if (i > n - 1 || i < 0) return 9999999; if ((mask >> i) & 1) return 9999999; // to check if a state has // been solved if (v[i][mask]) return dp[i][mask]; v[i][mask] = 1; // required recurrence relation dp[i][mask] = 1 + min(minSteps(arr, i - arr[i], (mask | (1 << i)), n), minSteps(arr, i + arr[i], (mask | (1 << i)), n)); // returning the value return dp[i][mask]; } // Driver code int main() { int arr[] = { 1, 2, 2, 2, 1, 1 }; int n = sizeof (arr) / sizeof ( int ); int ans = minSteps(arr, 0, 0, n); if (ans >= 9999999) cout << -1; else cout << ans; } |
Java
// Java implementation of the above approach class GFG { static int maxLen = 10 ; static int maskLen = 130 ; // variable to store states of dp static int [][] dp = new int [maxLen][maskLen]; // variable to check if a given state // has been solved static boolean [][] v = new boolean [maxLen][maskLen]; // Function to find the minimum number of steps // required to reach the end of the array static int minSteps( int arr[], int i, int mask, int n) { // base case if (i == n - 1 ) { return 0 ; } if (i > n - 1 || i < 0 ) { return 9999999 ; } if ((mask >> i) % 2 == 1 ) { return 9999999 ; } // to check if a state has // been solved if (v[i][mask]) { return dp[i][mask]; } v[i][mask] = true ; // required recurrence relation dp[i][mask] = 1 + Math.min(minSteps(arr, i - arr[i], (mask | ( 1 << i)), n), minSteps(arr, i + arr[i], (mask | ( 1 << i)), n)); // returning the value return dp[i][mask]; } // Driver code public static void main(String[] args) { int arr[] = { 1 , 2 , 2 , 2 , 1 , 1 }; int n = arr.length; int ans = minSteps(arr, 0 , 0 , n); if (ans >= 9999999 ) { System.out.println(- 1 ); } else { System.out.println(ans); } } } /* This code contributed by PrinciRaj1992 */ |
Python
# Python3 implementation of the above approach maxLen = 10 maskLen = 130 # variable to store states of dp dp = [[ 0 for i in range (maskLen)] for i in range (maxLen)] # variable to check if a given state # has been solved v = [[ False for i in range (maskLen)] for i in range (maxLen)] # Function to find the minimum number of steps # required to reach the end of the array def minSteps(arr, i, mask, n): # base case if (i = = n - 1 ): return 0 if (i > n - 1 or i < 0 ): return 9999999 if ((mask >> i) & 1 ): return 9999999 # to check if a state has # been solved if (v[i][mask] = = True ): return dp[i][mask] v[i][mask] = True # required recurrence relation dp[i][mask] = 1 + min (minSteps(arr, i - arr[i], (mask | ( 1 << i)), n), minSteps(arr, i + arr[i], (mask | ( 1 << i)), n)) # returning the value return dp[i][mask] # Driver code arr = [ 1 , 2 , 2 , 2 , 1 , 1 ] n = len (arr) ans = minSteps(arr, 0 , 0 , n) if (ans > = 9999999 ): print ( - 1 ) else : print (ans) # This code is contributed by mohit kumar 29 |
C#
// C# implementation of the above approach using System; class GFG { static int maxLen = 10; static int maskLen = 130; // variable to store states of dp static int [,] dp = new int [maxLen, maskLen]; // variable to check if a given state // has been solved static bool [,] v = new bool [maxLen, maskLen]; // Function to find the minimum number of steps // required to reach the end of the array static int minSteps( int []arr, int i, int mask, int n) { // base case if (i == n - 1) { return 0; } if (i > n - 1 || i < 0) { return 9999999; } if ((mask >> i) % 2 == 1) { return 9999999; } // to check if a state has // been solved if (v[i, mask]) { return dp[i, mask]; } v[i, mask] = true ; // required recurrence relation dp[i,mask] = 1 + Math.Min(minSteps(arr, i - arr[i], (mask | (1 << i)), n), minSteps(arr, i + arr[i], (mask | (1 << i)), n)); // returning the value return dp[i,mask]; } // Driver code static public void Main () { int []arr = {1, 2, 2, 2, 1, 1}; int n = arr.Length; int ans = minSteps(arr, 0, 0, n); if (ans >= 9999999) { Console.WriteLine(-1); } else { Console.WriteLine(ans); } } } /* This code contributed by ajit. */ |
Javascript
<script> // Javascript implementation of // the above approach let maxLen = 10; let maskLen = 130; // variable to store states of dp let dp = new Array(maxLen); for (let i = 0; i < maxLen; i++) { dp[i] = new Array(maskLen); } // variable to check if a given state // has been solved let v = new Array(maxLen); for (let i = 0; i < maxLen; i++) { v[i] = new Array(maskLen); } // Function to find the minimum number of steps // required to reach the end of the array function minSteps(arr, i, mask, n) { // base case if (i == n - 1) { return 0; } if (i > n - 1 || i < 0) { return 9999999; } if ((mask >> i) % 2 == 1) { return 9999999; } // to check if a state has // been solved if (v[i][mask]) { return dp[i][mask]; } v[i][mask] = true ; // required recurrence relation dp[i][mask] = 1 + Math.min(minSteps(arr, i - arr[i], (mask | (1 << i)), n), minSteps(arr, i + arr[i], (mask | (1 << i)), n)); // returning the value return dp[i][mask]; } let arr = [1, 2, 2, 2, 1, 1]; let n = arr.length; let ans = minSteps(arr, 0, 0, n); if (ans >= 9999999) { document.write(-1); } else { document.write(ans); } </script> |
3
Time Complexity: O(N*(2N))
Auxiliary Space: O(maxLen + maskLen)
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Steps to solve this problem :
- Create a DP to store the solution of the subproblems and initialize it with 9999999.
- Initialize the DP with base cases
- Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP
- At last return answer if exists in dp[n-1]
Implementation :
C++
// C++ code for above approach #include <bits/stdc++.h> #define maxLen 10 #define maskLen 130 using namespace std; // Function to find the minimum number of steps // required to reach the end of the array int minSteps( int arr[], int n) { // DP table to store solutions to subproblems int dp[n]; memset (dp, 9999999, sizeof (dp)); dp[0] = 0; // DP table to keep track of visited states bool v[n][maskLen]; memset (v, false , sizeof (v)); v[0][0] = true ; // Filling up the DP table using recurrence relation for ( int i = 0; i < n; i++) { for ( int j = 0; j < n; j++) { if (v[i][j]) { if (i + arr[i] < n) { dp[i + arr[i]] = min(dp[i + arr[i]], dp[i] + 1); v[i + arr[i]][j | (1 << i)] = true ; } if (i - arr[i] >= 0) { dp[i - arr[i]] = min(dp[i - arr[i]], dp[i] + 1); v[i - arr[i]][j | (1 << i)] = true ; } } } } // Returning the final answer if (dp[n-1] >= 9999999) return -1; return dp[n-1]; } // Driver code int main() { int arr[] = {1, 2, 2, 2, 1, 1}; int n = sizeof (arr) / sizeof (arr[0]); cout << minSteps(arr, n) << endl; return 0; } |
Java
import java.util.*; public class Main { static final int maxLen = 10 ; static final int maskLen = 130 ; // Function to find the minimum number of steps // required to reach the end of the array static int minSteps( int [] arr, int n) { // DP table to store solutions to subproblems int [] dp = new int [n]; Arrays.fill(dp, 9999999 ); dp[ 0 ] = 0 ; // DP table to keep track of visited states boolean [][] v = new boolean [n][maskLen]; for ( boolean [] row : v) { Arrays.fill(row, false ); } v[ 0 ][ 0 ] = true ; // Filling up the DP table using recurrence relation for ( int i = 0 ; i < n; i++) { for ( int j = 0 ; j < n; j++) { if (v[i][j]) { if (i + arr[i] < n) { dp[i + arr[i]] = Math.min(dp[i + arr[i]], dp[i] + 1 ); v[i + arr[i]][j | ( 1 << i)] = true ; } if (i - arr[i] >= 0 ) { dp[i - arr[i]] = Math.min(dp[i - arr[i]], dp[i] + 1 ); v[i - arr[i]][j | ( 1 << i)] = true ; } } } } // Returning the final answer if (dp[n- 1 ] >= 9999999 ) { return - 1 ; } return dp[n- 1 ]; } // Driver code public static void main(String[] args) { int [] arr = { 1 , 2 , 2 , 2 , 1 , 1 }; int n = arr.length; System.out.println(minSteps(arr, n)); } } |
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; class Program { // Maximum length of array static int maxLen = 10; // Maximum length of mask static int maskLen = 130; // Function to find the minimum number of steps // required to reach the end of the array static int minSteps( int [] arr, int n) { // DP table to store solutions to subproblems int [] dp = new int [n]; Array.Fill(dp, 9999999); dp[0] = 0; // DP table to keep track of visited states bool [][] v = new bool [n][]; for ( int i = 0; i < n; i++) { v[i] = new bool [maskLen]; Array.Fill(v[i], false ); } v[0][0] = true ; // Filling up the DP table using recurrence relation for ( int i = 0; i < n; i++) { for ( int j = 0; j < n; j++) { if (v[i][j]) { if (i + arr[i] < n) { dp[i + arr[i]] = Math.Min( dp[i + arr[i]], dp[i] + 1); v[i + arr[i]][j | (1 << i)] = true ; } if (i - arr[i] >= 0) { dp[i - arr[i]] = Math.Min( dp[i - arr[i]], dp[i] + 1); v[i - arr[i]][j | (1 << i)] = true ; } } } } // Returning the final answer if (dp[n - 1] >= 9999999) { return -1; } return dp[n - 1]; } // Driver code static void Main( string [] args) { int [] arr = { 1, 2, 2, 2, 1, 1 }; int n = arr.Length; Console.WriteLine(minSteps(arr, n)); } } |
Javascript
// Define maskLen as a constant variable const maskLen = 130; // Function to find the minimum number of steps // required to reach the end of the array function minSteps(arr, n) { // DP table to store solutions to subproblems const dp = new Array(n).fill(9999999); dp[0] = 0; // DP table to keep track of visited states const v = new Array(n).fill( false ).map(() => new Array(maskLen).fill( false )); v[0][0] = true ; // Filling up the DP table using recurrence relation for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) { if (v[i][j]) { if (i + arr[i] < n) { dp[i + arr[i]] = Math.min(dp[i + arr[i]], dp[i] + 1); v[i + arr[i]][j | (1 << i)] = true ; } if (i - arr[i] >= 0) { dp[i - arr[i]] = Math.min(dp[i - arr[i]], dp[i] + 1); v[i - arr[i]][j | (1 << i)] = true ; } } } } // Returning the final answer if (dp[n - 1] >= 9999999) return -1; return dp[n - 1]; } // Driver code const arr = [1, 2, 2, 2, 1, 1]; const n = arr.length; console.log(minSteps(arr, n)); |
Output:
3
Time Complexity: O(N*N)
Auxiliary Space: O(N+N+ maskLen)
Please Login to comment...