题目描述:
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1 输出:[1]
解题思路:
循环遍历数组中的元素,用一个双端队列Deque存储每次遍历的元素的下标,根据题目给出的滑动窗口的大小k以及用于循环遍历的 i 可以得到滑动窗口的起始位置:i - k + 1,由此也可以得到滑窗的末端位置为 i,在将元素下标加到Deque中前需要判断队头元素是否在滑窗之外(deque.peek() < i - k + 1),如果是的话则将队头元素出队,然后还需要判断目前数组中的元素是否大于队尾元素(nums[ i ] > nums[deque.peekLast()]),是的话则将队尾元素移除以保证队列中的元素都是单调递减的, 在滑窗值满足时可以将队列中元素所对应的值加入到结果数组中,之后就重复以上步骤直至遍历完毕。
代码如下:
public class SlidingWindowMax {
public static int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length == 0 || k <= 0 || k > nums.length) {
return new int[0];
}
int[] result = new int[nums.length - k + 1];
int index = 0;
// 创建一个双端队列来存储数组元素的下标
Deque<Integer> deque = new ArrayDeque<>();
for (int i = 0; i < nums.length; i++) {
// 移除窗口外的元素,即队列头部的元素不在当前窗口的范围内
while (!deque.isEmpty() && deque.peek() < i - k + 1) {
deque.poll();
}
// 移除队列中比当前元素小的元素,因为它们不可能成为窗口中的最大值
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
deque.pollLast();
}
// 添加当前元素下标到队列中
deque.offer(i);
// 当窗口完全覆盖时,记录窗口中的最大值,即队列头部的元素
if (i >= k - 1) {
result[index++] = nums[deque.peek()];
}
}
return result; // 返回结果数组
}