package All; import java.util.Deque; import java.util.LinkedList; /** * 题目: 1696. 跳跃游戏 VI * 描述:给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 * 一开始你在下标 0 处。每一步,你最多可以往前跳 k 步,但你不能跳出数组的边界。也就是说,你可以从下标 i 跳到 [i + 1, min(n - 1, i + k)] 包含 两个端点的任意位置。 * 你的目标是到达数组最后一个位置(下标为 n - 1 ),你的 得分 为经过的所有数字之和。 * 请你返回你能得到的 最大得分 。 示例 1: 输入:nums = [1,-1,-2,4,-7,3], k = 2 输出:7 解释:你可以选择子序列 [1,-1,4,3] (上面加粗的数字),和为 7 。 * 链接:https://leetcode.cn/problems/jump-game-vi/ */ //不会做 public class MaxResult { //超时 public int maxResult2(int[] nums, int k) { int n = nums.length; int[] f = new int[n]; f[0] = nums[0]; for (int i = 1; i < n; i++) { int mx = Integer.MIN_VALUE; for (int j = Math.max(i - k, 0); j < i; j++) { mx = Math.max(mx, f[j]); } f[i] = mx + nums[i]; } return f[n - 1]; } /* dp[i] = max(dp[j]) + nums[i],其中 j ∈ [i - k, i - 1]。 用一个双端队列存放“候选下标”,保持队列里的 dp 值是单调递减的,这样队首永远是最大值。 */ public int maxResult(int[] nums, int k) { int n = nums.length; int[] dp = new int[n]; dp[0] = nums[0]; Deque deque = new LinkedList<>(); deque.offer(0); // 队列存的是下标 for (int i = 1; i < n; i++) { // 队首如果滑出窗口 [i-k, i-1] 就移除 while (!deque.isEmpty() && deque.peek() < i - k) { deque.poll(); } // 队首就是窗口内 dp 最大值的下标 dp[i] = dp[deque.peek()] + nums[i]; // 保持队列单调递减:把比当前 dp[i] 小的值都踢掉 while (!deque.isEmpty() && dp[i] >= dp[deque.peekLast()]) { deque.pollLast(); } deque.offer(i); } return dp[n - 1]; } }