Jump Game Problem in Python

In this problem, we will have an array of integers. Each integer at a particular array index specifies the maximum length of jump we can make from that index. We have to find the number of jumps needed to reach the last index of the array. We have to return the minimum count of all. If the end cannot be reached through any path, we will return -1 for that array.

Let us see some examples to understand the problem.

Input: array = [1, 2, 6, 8, 6, 3, 6, 0, 1, 2, 9]

Output: 3 (1--> 2 --> 8 --> 9)

Explanation: We will start from the 0th index. The integer at the 0th index is 1; hence we can jump to the maximum 1st index. Next, from the 1st index, we can jump forward 2 indices. Therefore, we will reach index 3. From index 3, we can jump eight steps forward. Since 8 + 3 = 11, which is the array's length. Hence, from index 3, we will jump beyond the last index of the array. We made 3 jumps to reach the end. So the answer is 3.

Input: array = [1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1]

Output: 5

Explanation: We will apply the same logic as in the above example. We will jump from the 0th index to the 1st index, then to the 2nd index. From the 2nd index forward, we will jump two indices, going to the 4th, then the 6th, then the 8th, and the 10th index. The total count of jumps made to reach the last index is 10.

Approach - 1

In the first approach, we will use recursion to solve the problem.

We will first create a recursive function. We will recursively call the function for all the indices reached from the current element. We can calculate all the possible paths in the given array and find the shortest path or the path with minimum jumps.

We will follow the following steps to solve this problem.

  • We will first define a recursive function.
  • Then we will specify the base condition of this recursive function.
  • In the following step, we will call this function recursively. Through every recursive call, we will get all the indices that are reachable from the current index based on the jump limit. Hence, we will call this function for each index.
  • Then the last step is to find the minimum jumps needed to go to the last index of the array from the current index.
  • We will return the minimum jumps required.

Below is the Python program for the algorithm shown above.

Code

Output:

The minimum jumps required to reach the end of the array is: 3

Time complexity: There are at most n possible ways to move forward from any given index. Hence, the maximum steps required to reach the end will be nn. So the time complexity is O(n * Nn).

Space Complexity: We need O(n) memory to store the recursion stack.

Approach - 2

In the second approach, we will use dynamic programming. Some overlapping conditions take extra time; hence, using Dynamic Programming will be effective.

Let us understand through an example. Let us take the array = [1, 2, 1, 8, 6, 3, 6, 0, 1, 2, 9]. The recursive function minNoJumps(3, 10) will be called twice because one can reach 8 from the index 1 and 2. Hence, this is an overlapping sub-problem. We can avoid such overlapping sub-problems using a Dynamic Programming solution.

We will follow these steps to solve the problem:

  • We will create an array dp = []. We will fill the array dp such that dp[i] will store the minimum number of jumps required to get to index I starting from index 0. Initially, we will set dp[i] equal to float("inf").
  • We will fill this array using a nested Python loop.
  • The outer for loop will be in the range of 1 to n - 1, while the inner loop will be in the range of 0 to i.
  • If the value of i is less than j + array[j], then we will set dp[i] equal to the minimum value among the dp[i] and dp[i] + 1.
  • At last, we will return the value at the last index of the array dp.

Below is the Python code of the approach mentioned above.

Code

Output:

The minimum jumps required to reach the end of the array is: 3 

Time Complexity: This approach's time complexity is much reduced than the previous approach. The complexity is reduced because we do not need to run various sub-problems more than once. The time complexity is non-linear because of two nested loops; hence, it is O(n2).

Space Complexity: We are storing the dp array of length n, which will take the linear space in the memory. Hence, the space complexity of this approach is O(n).

Approach - 3

This approach is a variation of the dynamic programming approach we saw above.

We will again create an array dp = []. However, this time the ith index of dp will tell the minimum jumps one needs to reach the (n - 1)th index from the ith index of the array. Hence, at the end of the program, we will return the value of the first index, i.e., the 0th index of array dp. This approach will tell the minimum jumps required to reach the (n - 1)th index from the 0th index.

Below is the Python code for this approach.

Code

Output:

The minimum jumps required to reach the end of the array is: 3

Time complexity: Since we are running a nested loop, the time complexity will be non-linear. Hence, it is O(n2).

Space Complexity: We have used extra space to store the DP array. Hence

the space complexity is O(n).

Approach - 3

We will use a greedy algorithm to solve this problem in this approach.

Below are the steps to be followed.

  • First, we will check if the array is empty or contains a single element. If this condition is true, we are already at the end of the array, and hence, we will return 0 jumps.
  • Following the condition, we will check if the first element of the array is 0 or not. If the first element is 0, we cannot move forward and hence, cannot reach the end of the array. Hence, we will return -1.
  • We will initialize three variables. The first will contain the maximum reach, max_reach = 0, the second variable will keep track of the current reach curr_reach = 0, and the third variable will count the number of jumps, no_jumps = 0.
    • Now we will traverse the array from the first to the last.
    • Firstly we will check if the current index exceeds the maximum reach possible. If this condition is true, we cannot reach the end of the array, and hence we will return -1.
    • The following condition that we will check is if the value at the index I of the array is greater than the maximum reach till now. If yes, we can go beyond the current max_reach value. Hence, we will update the max_reach as i + array[i].
    • The last condition to check is whether the current index equals the curr_reach. If this condition is true, it means to go further, we need to jump. Hence, if this condition is true, we will increment the jump counter no_jumps. Also, we will update the curr_reach equal to the max_reach, which will check when we have to jump the next time.
  • At last, we have to return the number of jumps stored in the no_jumps variable.

Below is the Python program implementing the approach of the greedy algorithm.

Code

Output:

The minimum jumps required to reach the end of the array is: 3

Time complexity: We have executed a linear loop; hence time complexity will be linear. O(n).

Space Complexity: We have not used any extra space; therefore, the space complexity is constant, i.e., O(1).

The Greedy Algorithm is the best of all the approaches with linear time complexity and constant space complexity.






Latest Courses