达到末尾下标所需的最大跳跃次数
难度:
标签:
题目描述
You are given a 0-indexed array nums
of n
integers and an integer target
.
You are initially positioned at index 0
. In one step, you can jump from index i
to any index j
such that:
0 <= i < j < n
-target <= nums[j] - nums[i] <= target
Return the maximum number of jumps you can make to reach index n - 1
.
If there is no way to reach index n - 1
, return -1
.
Example 1:
Input: nums = [1,3,6,4,1,2], target = 2 Output: 3 Explanation: To go from index 0 to index n - 1 with the maximum number of jumps, you can perform the following jumping sequence: - Jump from index 0 to index 1. - Jump from index 1 to index 3. - Jump from index 3 to index 5. It can be proven that there is no other jumping sequence that goes from 0 to n - 1 with more than 3 jumps. Hence, the answer is 3.
Example 2:
Input: nums = [1,3,6,4,1,2], target = 3 Output: 5 Explanation: To go from index 0 to index n - 1 with the maximum number of jumps, you can perform the following jumping sequence: - Jump from index 0 to index 1. - Jump from index 1 to index 2. - Jump from index 2 to index 3. - Jump from index 3 to index 4. - Jump from index 4 to index 5. It can be proven that there is no other jumping sequence that goes from 0 to n - 1 with more than 5 jumps. Hence, the answer is 5.
Example 3:
Input: nums = [1,3,6,4,1,2], target = 0 Output: -1 Explanation: It can be proven that there is no jumping sequence that goes from 0 to n - 1. Hence, the answer is -1.
Constraints:
2 <= nums.length == n <= 1000
-109 <= nums[i] <= 109
0 <= target <= 2 * 109
代码结果
运行时间: 263 ms, 内存: 16.9 MB
/*
* 思路:
* 使用动态规划和Java Stream API来简化部分操作。
* 和上面的思路类似,维护一个dp数组来存储到达每个位置的最大跳跃次数。
* 使用IntStream遍历来实现动态规划的跳跃过程。
*/
import java.util.*;
import java.util.stream.*;
public class Solution {
public int maxJump(int[] nums, int target) {
int n = nums.length;
int[] dp = new int[n];
Arrays.fill(dp, -1);
dp[0] = 0;
IntStream.range(0, n).forEach(i -> {
if (dp[i] != -1) {
IntStream.range(i + 1, n).forEach(j -> {
if (nums[j] - nums[i] >= -target && nums[j] - nums[i] <= target) {
dp[j] = Math.max(dp[j], dp[i] + 1);
}
});
}
});
return dp[n - 1];
}
}
解释
方法:
该题解采用了线段树(ZKW线段树的非递归版本)来求解问题。首先,为了应对题目中允许的跳跃范围 [-target, target],题解将数组中的每个元素 x 扩展到三个可能的跳跃值 x-target, x, x+target,并去重排序。这种扩展允许在 O(log n) 时间内查询和更新任何区间的最大值。通过映射每个扩展值到其索引,可以用线段树高效查询和更新最大的跳跃次数。遍历 nums 数组,对于每个元素 x,查询在 [x-target, x+target] 范围内的最大跳跃次数,并在线段树中更新当前 x 的位置。最后,检查是否能到达 n-1 索引处,并返回相应的跳跃次数。如果不能到达,则返回 -1。
时间复杂度:
O(n log n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在处理跳跃范围时,选择将每个元素扩展为 x-target, x, x+target 三个可能的值?这种设计对算法的效率和结果有什么影响?
▷🦆
题解中提到的线段树(ZKW线段树的非递归版本)的具体实现细节是什么?特别是如何在非递归的情况下实现区间的查询和更新?
▷🦆
题解中的线段树初始化时为什么将每个元素默认值设为 -inf,这个选择对算法的执行有什么特别的意义或影响?
▷🦆
在算法的最后阶段,如果最终的跳跃次数 q 为负值,返回 -1 表示无法到达最后一个索引。这种情况是如何出现的?具体是在什么情况下会出现 q<0?
▷