Minimum number of jumps to reach end
Given an array of integers where each element represents the max number of steps that can be made forward from that element. Write a function to return the minimum number of jumps to reach the end of the array (starting from the first element). If an element is 0, then cannot move through that element.
Example:
Input: arr[] = {1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9}
Output: 3 (1-> 3 -> 8 ->9)
First element is 1, so can only go to 3. Second element is 3, so can make at most 3 steps eg to 5 or 8 or 9.
Method 1 (Naive Recursive Approach)
A naive approach is to start from the first element and recursively call for all the elements reachable from first element. The minimum number of jumps to reach end from first can be calculated using minimum number of jumps needed to reach end from the elements reachable from first.
minJumps(start, end) = Min ( minJumps(k, end) ) for all k reachable from start
#include <stdio.h>
#include <limits.h>
// Returns minimum number of jumps to reach arr[h] from arr[l]
int minJumps(int arr[], int l, int h)
{
// Base case: when source and destination are same
if (h == l)
return 0;
// When nothing is reachable from the given source
if (arr[l] == 0)
return INT_MAX;
// Traverse through all the points reachable from arr[l]. Recursively
// get the minimum number of jumps needed to reach arr[h] from these
// reachable points.
int min = INT_MAX;
for (int i = l+1; i <= h && i <= l + arr[l]; i++)
{
int jumps = minJumps(arr, i, h);
if(jumps != INT_MAX && jumps + 1 < min)
min = jumps + 1;
}
return min;
}
// Driver program to test above function
int main()
{
int arr[] = {1, 3, 6, 3, 2, 3, 6, 8, 9, 5};
int n = sizeof(arr)/sizeof(arr[0]);
printf("Minimum number of jumps to reach end is %d ", minJumps(arr, 0, n-1));
return 0;
}
If we trace the execution of this method, we can see that there will be overlapping subproblems. For example, minJumps(3, 9) will be called two times as arr[3] is reachable from arr[1] and arr[2]. So this problem has both properties (optimal substructure and overlapping subproblems) of Dynamic Programming.
Method 2 (Dynamic Programming)
In this method, we build a jumps[] array from left to right such that jumps[i] indicates the minimum number of jumps needed to reach arr[i] from arr[0]. Finally, we return jumps[n-1].
#include <stdio.h>
#include <limits.h>
// Returns minimum number of jumps to reach arr[n-1] from arr[0]
int minJumps(int arr[], int n)
{
int *jumps = new int[n]; // jumps[n-1] will hold the result
int i, j;
if (n == 0 || arr[0] == 0)
return INT_MAX;
jumps[0] = 0;
// Find the minimum number of jumps to reach arr[i]
// from arr[0], and assign this value to jumps[i]
for (i = 1; i < n; i++)
{
jumps[i] = INT_MAX;
for (j = 0; j < i; j++)
{
if (i <= j + arr[j] && jumps[j] != INT_MAX)
{
jumps[i] = jumps[j] + 1;
break;
}
}
}
return jumps[n-1];
}
// Driver program to test above function
int main()
{
int arr[]= {1, 3, 6, 1, 0, 9};
int size=sizeof(arr)/sizeof(int);
printf("Minimum number of jumps to reach end is %d ", minJumps(arr,size));
return 0;
}
Thanks to paras for suggesting this method.
Time Complexity: O(n^2)
Method 3 (Dynamic Programming)
In this method, we build jumps[] array from right to left such that jumps[i] indicates the minimum number of jumps needed to reach arr[n-1] from arr[i]. Finally, we return arr[0].
int minJumps(int arr[], int n)
{
int *jumps = new int[n]; // jumps[0] will hold the result
int min;
// Minimum number of jumps needed to reach last element
// from last elements itself is always 0
jumps[n-1] = 0;
int i, j;
// Start from the second element, move from right to left
// and construct the jumps[] array where jumps[i] represents
// minimum number of jumps needed to reach arr[m-1] from arr[i]
for (i = n-2; i >=0; i--)
{
// If arr[i] is 0 then arr[n-1] can't be reached from here
if (arr[i] == 0)
jumps[i] = INT_MAX;
// If we can direcly reach to the end point from here then
// jumps[i] is 1
else if (arr[i] >= n - i - 1)
jumps[i] = 1;
// Otherwise, to find out the minimum number of jumps needed
// to reach arr[n-1], check all the points reachable from here
// and jumps[] value for those points
else
{
min = INT_MAX; // initialize min value
// following loop checks with all reachable points and
// takes the minimum
for (j = i+1; j < n && j <= arr[i] + i; j++)
{
if (min > jumps[j])
min = jumps[j];
}
// Handle overflow
if (min != INT_MAX)
jumps[i] = min + 1;
else
jumps[i] = min; // or INT_MAX
}
}
return jumps[0];
}
Time Complexity: O(n^2) in worst case.
Thanks to Ashish for suggesting this solution.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Tweet
public class MinJumps { public static int getMinJumps(int a[]) { if (a == null || a.length == 0) { return -1; } for (int i = 0; i < a.length; ++i) { if (a[i] < 0) { return -1; } } int dp[] = new int[a.length]; dp[a.length - 1] = 0; for (int i = a.length - 2; i >= 0; --i) { int min = Integer.MAX_VALUE; for (int j = i + 1; j < a.length && j <= i + a[i]; ++j) { if (dp[j] != Integer.MAX_VALUE && 1 + dp[j] < min) { min = 1 + dp[j]; } } dp[i] = min; } System.out.println(dp[0]); return dp[0]; } public static void main(String args[]) { getMinJumps(new int[]{1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9}); getMinJumps(new int[]{1, 3, 6, 1, 0, 9}); getMinJumps(new int[]{1, 0, 1, 2}); } }why cant we select the maximum number in the range....plz tell me some examples where we cant follow this.....
Can someone pls give some suggestions on how do u construct the shortest jump sequence in naive recursion solution
@Bazinga, @AK & @iCodeS:
Thanks for suggesting new approaches. We will review these approaches and add to the original post.
Range Minimum Queries can be done using linear space and each update/query in O(logn) time. Segment Tree or BIT can be used for this purpose. This would reduce the complexity of finding minimum_of_{ dp[i+1], dp[i+1], ... dp[i+a[i]] } to O(log n) giving a overall O(n logn) solution.
Here is an O(n) solution without using space.
Every time I am choosing that node for which i+ar[i] is maximum.
Please do check.
int minjumps2(int arr[],int start,int final) { int i=0,j=0,min=0,temp=0,max=0,k=0; for(i=0;i<=final;) { temp=0; max=0; if(i+arr[i]>=final) { min++; break; } for(j=i+1;j<=i+arr[i] && j<=final;j++) { temp=j+arr[j]; if(temp>max) { max=temp; k=j; } } i=k; min++; } return min; }@iCodeS: Could you please provide more details of the approach. An example or pseudo code will be really helpful.
Taking your first input case
Input: arr[] = {1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9}
jump=0;
i=0;
at first arr[i]=1,so can jump only 1 node,so no choice
now i=1; jump++;
from here we can jump atmost 3 nodes
check if (i+arr[i]>=final) then we can reach from here in 1 jump
else
for 1jump= i+arr[i]=2+5=7
for 2jump= i+arr[i]=3+8=11
for 3jump= i+arr[i]=4+9=13
we will choose 3jump,since it gives maximum value
now jump++;
jump=2;
from here we can reach within 1jump;
so jump++;
jump=3 <----Answer
@iCodeS: Thanks for the explanation. The program doesn't seem to work for some cases. Please see this comment. Also, could you please provide details about the time complexity being O(n) (There is a nested loop in the program).
Begin from the end and for an index, look for the number fartherest away from it, that can reach it.
For ex,
arr[] = {1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9}
Start from 9.
6 is the farthest from 9 that can reach it.
So, 6 is included.
From 6, we find 5.
5 to 3.
3 to 1.
O(n) time.
@kv391: Sorry, I sill don't get it. 6 is not the farthest that can reach last 9, 8 is the farthest, right?
Also, the above doesn't work for {1, 0, 3}.
#include <stdio.h> #include <limits.h> int minjumps2(int arr[],int start,int final) { int i=0,j=0,min=0,temp=0,max=0,k=0; for(i=0; i<=final;) { temp=0; max=0; if(i+arr[i]>=final) { min++; break; } for(j=i+1; j<=i+arr[i] && j<=final; j++) { temp=j+arr[j]; if(temp>max) { max=temp; k=j; } } i=k; min++; } return min; } // Driver program to test above function int main() { int arr[] = {1, 0, 3}; int n = sizeof(arr)/sizeof(arr[0]); printf("Minimum number of jumps to reach end is %d \n", minjumps2(arr, 0, n-1)); return 0; }Yes, you are right.
Saw the flaw there. Its actually n-square time algorithm. :-/
in method 3
else if (arr[i] >= n - i - 1)
jumps[i] = 1;
looks wrong
the arr is storing the index of the element where you can jump to so for example arr[0] = 1 implies that go to index 1. Hence for i=n-2, this check would say arr[n-2]>=1, which is true even if this arr[n-2] is jumping backwards to say index 6.
got it
While traversing the array n, selection of max element from all possible jumps from a[i] and jumping to that maximum element location is not sufficient? Which will have time complexity of O(n) and space O(1)..
I think there is some problem in method 2 in the condition of inner for loop.
Correct me if m wrong..
The conditions look correct to me. Could you write the problem that you think is there, or some case for which it may not work.
taking the same example given in code
int arr[]= {1, 3, 6, 1, 0, 9};
for second method it will give INT_MAX in return because you are using
for (j = 0; j < i && i <= j + arr[j]; j++)
{
if ((jumps[j] + 1) < jumps[i])
jumps[i] = jumps[j] + 1;
}
here "j < i && i <= j + arr[j]" will prevent it from updating value after first iteration as the condition will fail after j = 1 and eventually all jump[i] after i = 1 will remain INT_MAX.
Here is my code for second method
#include<stdio.h>
#include<limits.h>
#include<stdlib.h>
int min_jump(int * arr,int size)
{
int i,j;
int * jump = (int *)malloc(size * sizeof(int));
jump[0] = 0;
if(arr[0] == 0)
return -1;
for(i = 1; i < size;i++)
{
jump[i] = INT_MAX;
for( j = 0; j < i; j++)
{
if((arr[j] + j) >= i)
{
jump[i] = jump[j]+1;
break;
}
}
}
for(i = 0; i < size;i++)
printf("\n%d\n",jump[i]);
return jump[size-1];
}
int main()
{
int arr[]= {1, 3, 6, 1, 0, 9};
int size=sizeof(arr)/sizeof(int);
int res = min_jump(arr,size);
if(res > 0)
printf("\nMinimum number of jumps to reach end is %d ",res);
else
printf("\nno minimum jump possible");
return 0;
}
please mention if any mistake found.Thanks.
@sandeep: Thanks for providing details. We have updated the code.
@Sandeep: We have also included the optimization in your code (breaking the loop). The only thing to change in your code is, add condition "jumps[j] != INT_MAX" before updating jumps[i] to jumps[j] + 1. For example your code will cause overflow for array {1, 0, 1, 2}.
one error in 3rd approach, here instead of
else if (arr[i] >= n - i) jumps[i] = 1;it should be
else if (arr[i] >= n - i - 1) jumps[i] = 1;secondly is there much of a difference between 2 and 3 ?
@kenny: Thanks for pointing this out. We have modified the condition. Keep it up!!
I hope I understood the question correctly. How about this ? For each index i , we want to find dp[i], the minimum jumps towards right we need to make to jump out.
dp[i] = 1 + min{ dp[i+1], dp[i+1], .... dp[i+A[i]] }
We fill in the dp[] array from right to left and all we want is, given a range [x...y], what is the minimum value among {dp[x], dp[x+1], ... ,dp[y] }, which can be easily done using O(n) space and O(log n) query time and O(log n) update time using simple Range Minimum Query ( eg: range trees ). Finally the answer is the minimum of dp[i]. Overall complexity O( n logn ) time and O(n) space.
@Bazinga: Thanks for suggesting a new method. The method looks good. We will soon add it to the original post. Keep it up!
In the second method, I think we have to first check if we can reach i from j before updating the value of jumps[i] in the inner loop. I am sorry, if I have missed something in the code.
Sorry,didnot see the condition given at the start of the loop.
Method 3 is the best, right?
yes, method 3 is the most efficient.
Why is method 3 efficient over method 2?