Algorithm/src/main/java/All/MaxResult.java

66 lines
2.2 KiB
Java
Raw Normal View History

2025-09-27 12:25:49 +08:00
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];
}
}