求最少跳跃次数
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
leetcode
DP
解题思路:
- 利用一个数组,表示到达每个位置最少跳跃次数。
- 遍历数组,然后对每个位置可以跳到的范围内的位置进行状态转移,保留次数少的。
- 时间复杂度是n方的。
class Solution {
public int jump(int[] nums) {
int n = nums.length;
int[] f = new int[n];
Arrays.fill(f, Integer.MAX_VALUE / 2);
f[0] = 0;
for(int i = 0; i < n; i++) {
for(int j = i; j <= nums[i] + i && j < n; j++) {
// 状态转移,比较从前一个位置跳过来的次数
f[j] = Math.min(f[i] + 1, f[j]);
}
}
return f[n - 1];
}
}
贪心
解题思路:维护一个范围内的最少跳跃次数,当超出该范围,那就不得不增加跳跃次数了。
class Solution {
public int jump(int[] nums) {
int res = 0;
int max = 0, end = 0;
for(int i = 0; i < nums.length - 1; i++) {
max = Math.max(max, nums[i] + i);
// 到达一个范围的终点,说明之前一跳不可能超过这个位置,所以跳跃次数必须增加
if(end == i) {
res += 1;
end = max;
}
}
return res;
}
}
求最高得分
给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。
一开始你在下标 0 处。每一步,你最多可以往前跳 k 步,但你不能跳出数组的边界。也就是说,你可以从下标 i 跳到 [i + 1, min(n - 1, i + k)] 包含 两个端点的任意位置。
你的目标是到达数组最后一个位置(下标为 n - 1 ),你的 得分 为经过的所有数字之和。
请你返回你能得到的 最大得分 。
leetcode
解题思路:这是一道非常常规的单调队列的题。
- 首先想到利用DP的做法,每个位置的最优解就是前面k个的最优解加上这个位置的分值。
- 但如是如果每次都去求前面k个解的最大值,时间复杂度就是nk的,这里会超时。
- 所以,这里其实就是一个滑动窗口,利用单调队列就能快速求窗口内的最大值了。
class Solution {
public int maxResult(int[] nums, int k) {
int n = nums.length;
Deque<Integer> q = new LinkedList<>();
int[] f = new int[n];
// 填入初始值
f[0] = nums[0];
q.offerLast(f[0]);
for(int i = 1; i < n; i++) {
// 超出步数的元素出队
if(i > k && q.peekFirst() == f[i - k - 1]) q.poll();
// 计算当前值
f[i] = nums[i] + q.peekFirst();
// 当前值入队
while(!q.isEmpty() && q.peekLast() <= f[i]) q.pollLast();
q.offerLast(f[i]);
}
return f[n - 1];
}
}