Skip to content

Commit 709afbe

Browse files
committed
refactor(algorithms, greedy): jump game alternative solution
1 parent e7de547 commit 709afbe

16 files changed

+219
-104
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Jump Game
2+
3+
You are given an integer array nums. You are initially positioned at the array's first index, and each element in the
4+
array represents your maximum jump length at that position.
5+
6+
Return true if you can reach the last index, or false otherwise.
7+
8+
```text
9+
Example 1:
10+
11+
Input: nums = [2,3,1,1,4]
12+
Output: true
13+
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
14+
```
15+
16+
```text
17+
Example 2:
18+
19+
Input: nums = [3,2,1,0,4]
20+
Output: false
21+
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible
22+
to reach the last index.
23+
```
24+
25+
---
26+
27+
## Jump Game II
28+
29+
You are given a 0-indexed array of integers nums of length n. You are initially positioned at nums[0].
30+
31+
Each element nums[i] represents the maximum length of a forward jump from index i. In other words, if you are at
32+
nums[i], you can jump to any nums[i + j] where:
33+
34+
0 <= j <= nums[i] and
35+
i + j < n
36+
Return the minimum number of jumps to reach nums[n - 1]. The test cases are generated such that you can reach
37+
nums[n - 1].
38+
39+
```text
40+
Example 1:
41+
42+
Input: nums = [2,3,1,1,4]
43+
Output: 2
44+
Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to
45+
the last index.
46+
```
47+
48+
```text
49+
Example 2:
50+
51+
Input: nums = [2,3,0,1,4]
52+
Output: 2
53+
```
54+
55+
---
56+
57+
## Topics
58+
59+
- Array
60+
- Dynamic Programming
61+
- Greedy
62+
63+
## Solutions
64+
65+
1. [Naive Approach](#naive-approach)
66+
1. [Optimized Approach using Greedy Pattern](#optimized-approach-using-greedy-pattern)
67+
68+
### Naive Approach
69+
70+
The naive approach explores all possible jump sequences from the starting position to the end of the array. It begins
71+
at the first index and attempts to jump to every reachable position from the current index, recursively repeating this
72+
process for each new position. If a path successfully reaches the last index, the algorithm returns success. If it
73+
reaches a position without further moves, it backtracks to try a different path.
74+
75+
While this method guarantees that all possible paths are considered, it is highly inefficient, as it explores many
76+
redundant or dead-end routes. The time complexity of this backtracking approach is exponential, making it impractical
77+
for large inputs.
78+
79+
### Optimized Approach using Greedy Pattern
80+
81+
An optimized way to solve this problem is using a greedy approach that works in reverse. Instead of trying every
82+
possible forward jump, we flip the logic: start from the end and ask, “Can we reach this position from any earlier index?”
83+
84+
We begin with the last index as our initial target—the position we want to reach. Then, we move backward through the
85+
array, checking whether the current index has a jump value large enough to reach or go beyond the current target. If it
86+
can, we update the target to that index. This means that reaching this earlier position would eventually allow us to
87+
reach the end. By continuously updating the target, we’re effectively identifying the leftmost position from which the
88+
end is reachable.
89+
90+
This process continues until we reach the first index or determine that no earlier index can reach the current target.
91+
If we finish with the target at index 0, it means the start of the array can lead to the end, so we return TRUE. If the
92+
target remains beyond index 0, then no path exists from the start to the end, and we return FALSE.
93+
94+
![Solution 1](./images/solutions/jump_game_1_solution_1.png)
95+
![Solution 2](./images/solutions/jump_game_1_solution_2.png)
96+
![Solution 3](./images/solutions/jump_game_1_solution_3.png)
97+
![Solution 4](./images/solutions/jump_game_1_solution_4.png)
98+
![Solution 5](./images/solutions/jump_game_1_solution_5.png)
99+
![Solution 6](./images/solutions/jump_game_1_solution_6.png)
100+
![Solution 7](./images/solutions/jump_game_1_solution_7.png)
101+
![Solution 8](./images/solutions/jump_game_1_solution_8.png)
102+
![Solution 9](./images/solutions/jump_game_1_solution_9.png)
103+
![Solution 10](./images/solutions/jump_game_1_solution_10.png)
104+
![Solution 11](./images/solutions/jump_game_1_solution_11.png)
105+
106+
#### Algorithm
107+
108+
1. We begin by setting the last index of the array as our initial target using the variable target = len(nums) - 1. This
109+
target represents the position we are trying to reach, starting from the end and working backward. By initializing the
110+
target this way, we define our goal: to find out if there is any index i from which the target is reachable based on the
111+
value at that position, nums[i]. This also sets the stage for updating the target if such an index is found.
112+
113+
2. Next, we loop backward through the array using for i in range(len(nums) - 2, -1, -1). Here, i represents the current
114+
index we are analyzing. At each index i, the value nums[i] tells us how far we can jump forward from that position.
115+
By checking whether i + nums[i] >= target, we determine whether it can reach the current target from index i. This
116+
step allows us to use the jump range at each position to decide if it can potentially lead us to the end.
117+
118+
3. If the condition i + nums[i] >= target is TRUE, the current index i can jump far enough to reach the current target.
119+
In that case, we update target = i, effectively saying, “Now we just need to reach index i instead.” If the condition
120+
fails, we move back in the array one step further and try again with the previous index.
121+
We repeat this process until we either:
122+
- Successfully moving the target back to index 0 means the start of the array can reach the end. In this case, we
123+
return TRUE.
124+
- Or reach the start without ever being able to update the target to 0, which means there is no valid path. In this
125+
case, we return FALSE.
126+
127+
#### Solution Summary
128+
129+
1. Set the last index of the array as the target index.
130+
2. Traverse the array backward and verify if we can reach the target index from any of the previous indexes.
131+
- If we can reach it, we update the target index with the index that allows us to jump to the target index.
132+
- We repeat this process until we’ve traversed the entire array.
133+
3. Return TRUE if, through this process, we can reach the first index of the array. Otherwise, return FALSE.
134+
135+
#### Time Complexity
136+
137+
The time complexity of the above solution is O(n), since we traverse the array only once, where n is the number of
138+
elements in the array.
139+
140+
#### Space Complexity
141+
142+
The space complexity of the above solution is O(1), because we do not use any extra space.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33

44
def can_jump(nums: List[int]) -> bool:
5+
"""
6+
This function checks if it is possible to reach the last index of the array from the first index.
7+
Args:
8+
nums(list): list of integers
9+
Returns:
10+
bool: True if can jump to the last index, False otherwise
11+
"""
12+
513
current_position = nums[0]
614

715
for idx in range(1, len(nums)):
@@ -14,6 +22,28 @@ def can_jump(nums: List[int]) -> bool:
1422

1523
return True
1624

25+
def can_jump_2(nums: List[int]) -> bool:
26+
"""
27+
This function checks if it is possible to reach the last index of the array from the first index.
28+
29+
This variation starts checking from the last element in the input list and tracking back to check if it is possible
30+
to reach the end.
31+
32+
Args:
33+
nums(list): list of integers
34+
Returns:
35+
bool: True if can jump to the last index, False otherwise
36+
"""
37+
target_num_index = len(nums) - 1
38+
39+
for idx in range(len(nums) - 2, -1, -1):
40+
if target_num_index <= idx + nums[idx]:
41+
target_num_index = idx
42+
43+
if target_num_index == 0:
44+
return True
45+
return False
46+
1747

1848
def jump(nums: List[int]) -> int:
1949
size = len(nums)
45.3 KB
Loading
42.2 KB
Loading
43.3 KB
Loading
31.6 KB
Loading
46.3 KB
Loading
60.2 KB
Loading
35 KB
Loading
51.4 KB
Loading

0 commit comments

Comments
 (0)