Jump Game III
MedPrompt
Given an array of non-negative integers arr, you are initially positioned at start index of the array. When you are at index i, you can jump to i + arr[i] or i - arr[i], check if you can reach any index with value 0.
Notice that you can not jump outside of the array at any time.
Example 1:
Input: arr = [4,2,3,0,3,1,2], start = 5
Output: true
Explanation:
All possible ways to reach at index 3 with value 0 are:
index 5 -> index 4 -> index 1 -> index 3
index 5 -> index 6 -> index 4 -> index 1 -> index 3 Example 2:
Input: arr = [4,2,3,0,3,1,2], start = 0
Output: true
Explanation:
One possible way to reach at index 3 with value 0 is:
index 0 -> index 4 -> index 1 -> index 3Example 3:
Input: arr = [3,0,2,1,2], start = 2
Output: false
Explanation: There is no way to reach at index 1 with value 0.
Constraints:
1 <= arr.length <= 5 * 1040 <= arr[i] < arr.length0 <= start < arr.length
Approaches
3 approaches with complexity analysis and trade-offs.
This approach models the problem as a graph traversal. The array indices are the nodes, and the possible jumps define the edges. We use Depth-First Search (DFS) to explore all reachable indices from the start index. To prevent getting stuck in infinite loops (cycles), we use an auxiliary boolean array visited to keep track of the indices we have already explored.
Algorithm
- Initialize a boolean array
visitedof sizearr.lengthto allfalse. - Define a recursive function
dfs(index): a. Ifindexis out of bounds orvisited[index]is true, returnfalse. b. Ifarr[index] == 0, returntrue. c. Markvisited[index] = true. d. Explore right:foundRight = dfs(index + arr[index]). e. Explore left:foundLeft = dfs(index - arr[index]). f. ReturnfoundRight || foundLeft. - Call
dfs(start)and return its result.
Walkthrough
The algorithm starts a recursive traversal from the start index.
A visited array of the same size as the input array arr is initialized to all false.
The recursive function canReachRecursive(currentIndex, arr, visited) works as follows:
- Base Case (Out of Bounds): If
currentIndexis less than 0 or greater than or equal toarr.length, it's an invalid jump. Returnfalse. - Base Case (Already Visited): If
visited[currentIndex]istrue, we have already been at this index. To avoid a cycle, we returnfalse. - Base Case (Target Found): If
arr[currentIndex]is 0, we have reached a target index. Returntrue. - Mark as Visited: Set
visited[currentIndex] = trueto mark that we are currently exploring from this index. - Recursive Step: Explore the two possible jumps:
- Jump forward:
canReachRecursive(currentIndex + arr[currentIndex], arr, visited) - Jump backward:
canReachRecursive(currentIndex - arr[currentIndex], arr, visited)
- Jump forward:
- If either of the recursive calls returns
true, it means a path to a 0 exists, so we returntrue. Otherwise, returnfalse. The main function initializes thevisitedarray and calls the recursive function with thestartindex.
class Solution { public boolean canReach(int[] arr, int start) { boolean[] visited = new boolean[arr.length]; return canReachRecursive(arr, start, visited); } private boolean canReachRecursive(int[] arr, int index, boolean[] visited) { // Base case: out of bounds if (index < 0 || index >= arr.length) { return false; } // Base case: already visited if (visited[index]) { return false; } // Base case: target found if (arr[index] == 0) { return true; } // Mark as visited visited[index] = true; // Recursive step boolean found = canReachRecursive(arr, index + arr[index], visited) || canReachRecursive(arr, index - arr[index], visited); return found; }}Complexity
Time
O(N), where N is the length of the array. Each index is visited at most once.
Space
O(N). This is composed of O(N) for the `visited` array and O(N) for the recursion call stack in the worst-case scenario (e.g., a long chain of jumps).
Trade-offs
Pros
Conceptually simple and directly translates the problem's recursive nature.
Correctly handles cycles.
Cons
Can lead to a
StackOverflowErrorfor very deep recursion paths (long chains of jumps).Uses extra space for both the
visitedarray and the recursion stack.
Solutions
Solution
class Solution {public boolean canReach(int[] arr, int start) { Deque<Integer> q = new ArrayDeque<>(); q.offer(start); while (!q.isEmpty()) { int i = q.poll(); if (arr[i] == 0) { return true; } int x = arr[i]; arr[i] = -1; for (int j : List.of(i + x, i - x)) { if (j >= 0 && j < arr.length && arr[j] >= 0) { q.offer(j); } } } return false; }}Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.