LeetCode 每日一题笔记
0. 前言
- 日期:2026.05.10
- 题目:2770. 达到末尾下标所需的最大跳跃次数
- 难度:中等
- 标签:数组、动态规划、递归
1. 题目理解
问题描述 :
给你一个下标从 0 开始、由 n 个整数组成的数组 nums 和一个整数 target。
你初始位置在下标 0。在一步操作中,你可以从下标 i 跳跃到任意满足下述条件的下标 j:
- 0 ≤ i < j < n
- -target ≤ nums[j] - nums[i] ≤ target
返回到达下标 n-1 处所需的最大跳跃次数。
如果无法到达下标 n-1,返回 -1。
示例:
输入:nums = [1,3,6,4,1,2], target = 2
输出:3
解释:最大跳跃次数路径为:0 → 1 → 3 → 5,共3次跳跃。
2. 解题思路
核心观察
- 这是一道典型的动态规划问题,定义
dp[i]为从位置i到达终点所需的最大跳跃次数。 - 从后往前递推,终点
dp[n-1] = 0,对于位置i,所有满足条件的j(i < j且|nums[j]-nums[i]| ≤ target),dp[i] = max(dp[j] + 1)。 - 使用递归+记忆化的方式,从终点向前处理,避免重复计算。
算法步骤
- 初始化
dp数组,所有元素设为Integer.MIN_VALUE,表示不可达,终点dp[n-1] = 0。 - 从终点向前递归处理每个位置:
- 若当前位置
dp[index]已计算,则更新所有可跳跃到它的前驱位置的dp值。 - 递归处理前一个位置。
- 若当前位置
- 递归结束后,若
dp[0]仍为Integer.MIN_VALUE,说明不可达,返回 -1;否则返回dp[0]。
3. 代码实现
java
package lc2770;
import java.util.Arrays;
class Solution {
public void dp(int[] nums, int[] dp, int index, int target) {
if (index == 0) {
return;
}
if (dp[index] != Integer.MIN_VALUE) {
for (int i = 0; i < index; i++) {
int a = nums[index] - nums[i];
if (a <= target && a >= -target) {
dp[i] = dp[index] + 1 > dp[i] ? dp[index] + 1 : dp[i];
}
}
}
dp(nums, dp, index - 1, target);
}
public int maximumJumps(int[] nums, int target) {
int[] dp = new int[nums.length];
Arrays.fill(dp, Integer.MIN_VALUE);
dp[nums.length - 1] = 0;
dp(nums, dp, nums.length - 1, target);
if (dp[0] == Integer.MIN_VALUE) return -1;
else return dp[0];
}
}
4. 代码优化说明
- 该递归实现从后往前处理,每个位置仅被处理一次,避免了暴力枚举所有路径的指数级复杂度。
- 无需额外的递归栈外空间,直接在
dp数组上原地更新。
5. 复杂度分析
- 时间复杂度 :O(n2)O(n^2)O(n2),两层循环遍历所有位置对。
- 空间复杂度 :O(n)O(n)O(n),
dp数组占用线性空间,递归栈深度为 O(n)O(n)O(n)。
6. 总结
- 核心思路是从后往前的动态规划 ,定义
dp[i]为从i到终点的最大跳跃次数。 - 关键技巧是利用递归从终点向前更新前驱位置的
dp值,避免重复计算。 - 时间复杂度为 O(n2)O(n^2)O(n2),是该问题的标准解法。