队列
队列是一种先进先出(FIFO) 的数据结构,与栈不同,就像排队一样。通常仅允许在队尾查看与添加元素,在队头查看与删除元素。
队列通常由双链表实现,即头指针仅允许在队头查看与删除元素,尾指针在队尾添加元素。
应用场景:当需要按照顺序来处理数据时,可使用队列来解决问题,例如广度优先搜索,或者是🌲树的层级遍历均可以使用队列实现。
双端队列
与队列不同,可同时在队尾与队头添加删除与查看数据。
应用场景:实现一个长度动态变化的窗口或连续区间,动态窗口这种数据结构。
239 滑动窗口的最大值
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
来源:力扣(LeetCode)
示例:
输入: 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
提示:你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。
-
暴力解法
仍然是遍历就完事了,注意空数组,k=0的特殊入参校验就好了。
class Solution { public int[] maxSlidingWindow(int[] nums, int k) { int[] res = new int[nums.length-k+1]; if(res.length<1|| k==0){ return new int[k]; } for (int i = 0; i +k-1<nums.length; i++) { int max = nums[i]; for (int j = i; j <i+k ; j++) { if (nums[j]>max){ max = nums[j]; } } res[i] = max; } return res; }
- 使用双端队列
看了leetcode的官方题解与一个算法课中的题解都不是很理解,最后扒出来一个好理解的题解(https://leetcode-cn.com/problems/sliding-window-maximum/solution/shuang-xiang-dui-lie-jie-jue-hua-dong-chuang-kou-2/),然后自己撸了一遍才明白, 但还是不太明白是如何想到的使用双端队列这种数据结构。对我而言这个题的难点在于哪一步为结果数组赋值,以及如何维护该队列,还有就是边界值的判断。思路如下:
我们使用一个双端队列保存当前滑动窗口中的最大值的下标,并保证队头始终是当前滑动窗口的最大值下标,凡事当前元素大于队尾元素的,队尾均出队;因此,该队列从队头到队尾始终是从大到小的,我们在每次获得结果时,只需要取队头元素即可;
另外需要注意就是,要判断队头元素是否还在当前滑动窗口,如果不在应及时出队,使用L,R分别表示当前滑动窗口的左右两端,其中i为R,i-k 为L ;判断条件即 deque.peekFirst() <= i - k
另外在刚开始遍历数组时,滑动窗口不能达到k的长度,因此也获取不结果,也应做边界判断,即i-k+1>=0
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length < 2) {
return nums;
}
int[] res = new int[nums.length - k + 1];
Deque deque = new LinkedList();
for (int i = 0; i < nums.length; i++) {
//确保队列从队头到队尾从大到小
while (!deque.isEmpty() && nums[(int) deque.peekLast()] <= nums[i]) {
deque.pollLast();
}
deque.addLast(i);
//判断队头元素是否还在窗口中
if ((int) deque.peekFirst() <= i - k) {
deque.pollFirst();
}
//判断窗口长度是否达到k
if (i - k + 1 >= 0) {
res[i - k + 1] = nums[(int)deque.peekFirst()] ;
}
}
return res;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。