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];
|
|||
|
|
}
|
|||
|
|
}
|