66 lines
2.2 KiB
Java
66 lines
2.2 KiB
Java
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<Integer> 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];
|
||
}
|
||
}
|