Input: nums =[2,3,1,1,4]Output: 2Explanation: The minimum number of jumps to reach the last index is2. Jump 1 step from index 0 to 1, then 3 steps to the last index.
We observe that many subproblems are solved multiple times in the purely recursive approach. By using dynamic programming and memoization, we can store the results of these subproblems and use the stored results instead of recomputing them, thereby optimizing our solution.
publicclassSolution {
HashMap<Integer, Integer> memo =new HashMap<>();
privateintjump(int[] nums, int startIndex) {
// If reached the end, return 0if (startIndex == nums.length- 1) {
return 0;
}
// If the result is already computed, use itif (memo.containsKey(startIndex)) {
return memo.get(startIndex);
}
int size = nums.length;
int remainingLength = size - startIndex;
// If remaining length can be covered in one jump, return 1if (remainingLength <= nums[startIndex]) {
return 1;
}
// If current position is zero, can't move furtherif (nums[startIndex]== 0) {
return Integer.MAX_VALUE;
}
int jumps = Integer.MAX_VALUE;
// Try every jump length from 1 to nums[startIndex]for (int i = 1; i <= nums[startIndex]; i++) {
int temp = jump(nums, startIndex + i);
if (temp != Integer.MAX_VALUE) {
jumps = Math.min(jumps, 1 + temp);
}
}
memo.put(startIndex, jumps);
return jumps;
}
}
classSolution:
def __init__(self):
self.memo: Dict[int, int] = {}
defjump(self, nums: List[int], start: int =0) -> int:
# If reached the end, return 0if start == len(nums) -1:
return0# If the result is already computed, use itif start in self.memo:
return self.memo[start]
size = len(nums)
remaining_length = size - start
# If remaining length can be covered in one jump, return 1if remaining_length <= nums[start]:
return1# If current position is zero, can't move furtherif nums[start] ==0:
return float('inf')
jumps = float('inf')
# Try every jump length from 1 to nums[start]for i in range(1, nums[start] +1):
temp = self.jump(nums, start + i)
if temp != float('inf'):
jumps = min(jumps, 1+ temp)
self.memo[start] = jumps
return jumps
The solution is based on a greedy approach where we track the maximum steps of the last jump:
For each position, we calculate the farthest point that can be reached.
The main idea is to keep track of the range of the current jump [curBegin, curEnd] and the farthest point curFarthest that all points in [curBegin, curEnd] can reach.
Once the current index reaches curEnd, trigger another jump, and set curEnd to curFarthest. Continue this process until we either reach the end of the array or determine that it’s impossible.
Initialize: Start with the first index. Track the current jump range [curBegin, curEnd] and the farthest index that all points in this range can reach (curFarthest).
Iterate: Traverse the array and for each index, update curFarthest.
Trigger Jumps: When the current index reaches curEnd, increment the jump count and set curEnd to curFarthest.
End Check: If curEnd reaches or exceeds the last index, return the number of jumps.
publicclassSolution {
publicintjump(int[] nums) {
if (nums.length<= 1) {
return 0;
}
int jumps = 0;
int curEnd = 0;
int curFarthest = 0;
for (int i = 0; i < nums.length- 1; i++) {
curFarthest = Math.max(curFarthest, i + nums[i]);
if (i == curEnd) {
jumps++;
curEnd = curFarthest;
if (curEnd >= nums.length- 1) {
break;
}
}
}
return jumps;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
classSolution:
defjump(self, nums: List[int]) -> int:
if len(nums) <=1:
return0 jumps: int =0 cur_end: int =0 cur_farthest: int =0for i in range(len(nums) -1):
cur_farthest = max(cur_farthest, i + nums[i])
if i == cur_end:
jumps +=1 cur_end = cur_farthest
if cur_end >= len(nums) -1:
breakreturn jumps