题目
https://leetcode-cn.com/problems/sliding-window-maximum/
方法一:单调队列
https://blog.csdn.net/weixin_42970433/article/details/109174079
方法二:动态规划
分析
right[i] 是左侧块内的最大元素, left[j] 是右侧块内的最大元素。因此滑动窗口中的最大元素为 max(right[i], left[j])。
复杂度
时间复杂度:O(N),我们对长度为 N 的数组处理了 3次。
空间复杂度:O(N),用于存储长度为 N 的 left 和 right 数组,以及长度为 N - k + 1的输出数组。
代码
public int[] maxSlidingWindow(int[] nums, int k) {
int len = nums.length;
int[] maxLeft = new int[len];
int[] maxRight = new int[len];
//从左往右窗口的第一个最大值默认是数组第一个值
maxLeft[0] = nums[0];
//从右往左窗口的最后一个最大值是数组的最后一个值
maxRight[len - 1] = nums[len - 1];
for (int i = 1; i < len; i++) {
//这里分别计算从前往后窗口的最大值和从后往前窗口的最大值。要搞懂这里的判断,如果
//i % k == 0,表示到了下一个窗口
maxLeft[i] = (i % k == 0) ? nums[i] : Math.max(maxLeft[i - 1], nums[i]);
int j = len - i - 1;
maxRight[j] = ((j + 1) % k == 0) ? nums[j] : Math.max(maxRight[j + 1], nums[j]);
}
//返回的结果值
int[] res = new int[len - k + 1];
for (int i = 0, j = 0; i < res.length; i++) {
//取每个窗口内从左往右扫描的最后一个值和从右往左扫描的最后
//一个值(如果从左边数是第一个)的最大值
res[j++] = Math.max(maxRight[i], maxLeft[i + k - 1]);
}
return res;
}
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
if (n * k == 0) return new int[0];
if (k == 1) return nums;
int [] left = new int[n];
left[0] = nums[0];
int [] right = new int[n];
right[n - 1] = nums[n - 1];
for (int i = 1; i < n; i++) {
// from left to right
//某一组的第一个
if (i % k == 0)
left[i] = nums[i];
else
left[i] = Math.max(left[i - 1], nums[i]);
// from right to left
int j = n - i - 1;
//j某一组的最后第一个
if ((j + 1) % k == 0)
right[j] = nums[j]; // block_end
else
right[j] = Math.max(right[j + 1], nums[j]);
}
int [] output = new int[n - k + 1];
for (int i = 0; i < n - k + 1; i++)
output[i] = Math.max(left[i + k - 1], right[i]);
return output;
}
}