LeetCode_Queue_239. Sliding Window Maximum 滑动窗口最大值【优先队列,单调队列】【java】【中等】
2021/12/3 22:06:41
本文主要是介绍LeetCode_Queue_239. Sliding Window Maximum 滑动窗口最大值【优先队列,单调队列】【java】【中等】,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录
一,题目描述
英文描述
中文描述
示例与说明
二,解题思路
1,优先队列
2,单调队列
三,AC代码
Java
优先队列
单调对列
四,解题过程
第一搏
第二搏
第三搏
一,题目描述
英文描述
You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.
Return the max sliding window.
中文描述
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例与说明
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sliding-window-maximum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二,解题思路
参考@力扣官方题解【滑动窗口最大值】
1,优先队列
最直观的解法就是采用优先队列。
队列中包括滑动区间内的所有值。每次取值时,判断队头是否属于滑动区间内的元素,若不是则弹出,否则直接返回即可。
为了方便的判断元素位置,可以考虑在优先队列中存放大小为2的数组(位置1:元素值,位置2:元素下标)。
2,单调队列
优先队列的作用主要是为了获得滑动窗口内的最大值,然而若只是想获得窗口内最大值的话,维持一个普通队列就可以了。
- 当向队尾插入一个元素时,只需要将队列中小于等于该元素的值从后向前依次弹出即可;
- 若队头元素不属于滑动区间范围内,则从前向后弹出即可;
这样队头的元素一定是最大,且最新的(位于滑动窗口右侧,相较于左侧淘汰的晚些);
可以从上面看出,队列需要支持队头和队尾操作,因此我们采用双端队列。
此外,为了方便的判断元素的位置,队列中存放的值应该为数组中元素对应的下标(有下标后就可以很方便的获得对应的值)。因此队列中存放的值(数组下标)总保持递增的顺序,也就是通常所说的单调队列。
三,AC代码
Java
优先队列
class Solution { public int[] maxSlidingWindow(int[] nums, int k) { // int[2]:位置0表示元素大小,位置1表示元素位置 PriorityQueue<int[]> heap = new PriorityQueue<>(new Comparator<int[]>(){ public int compare(int[] a, int[] b) { // 元素大小不等时,按照大根堆的方法比较 // 元素大小相等时,位置越小,优先级越高,越先被弹出 return a[0] != b[0] ? b[0] - a[0] : a[1] - b[1]; } }); int[] ans = new int[nums.length - k + 1]; for (int i = 0; i < k - 1; i++) { heap.offer(new int[]{nums[i], i}); } for (int i = k - 1; i < nums.length; i++) { heap.offer(new int[]{nums[i], i}); while (heap.peek()[1] < i - k + 1) { heap.poll(); } ans[i - k + 1] = heap.peek()[0]; } return ans; } }
单调对列
class Solution { public int[] maxSlidingWindow(int[] nums, int k) { Deque<Integer> queue = new LinkedList<>(); // 将前k-1个数放入队列中 for (int i = 0; i < k - 1; i++) { while (!queue.isEmpty() && nums[i] >= nums[queue.peekLast()]) {// !!!加上等于 !!!这里需要与队列末尾进行比较,而不是队头 queue.pollLast(); } queue.offerLast(i); } int[] ans = new int[nums.length - k + 1]; // 从k-1开始遍历数组 for (int i = k - 1; i < nums.length; i++) { // 若队尾元素小于当前元素,则弹出队尾 while (!queue.isEmpty() && nums[i] >= nums[queue.peekLast()]) {// !!!加上等于 queue.pollLast(); } queue.offerLast(i); // 将队头超过滑动窗口区间的元素弹出 while (queue.peekFirst() < i - k + 1) { queue.pollFirst(); } ans[i - k + 1] = nums[queue.peekFirst()]; } return ans; } }
四,解题过程
第一搏
维护大小为k的大根堆,滑动窗口每移动一格,删除原窗口中第一个元素(heap.remove(nums[i])),将新窗口最后一个元素添加到堆中,返回堆顶即可。
class Solution { public int[] maxSlidingWindow(int[] nums, int k) { PriorityQueue<Integer> heap = new PriorityQueue<>(new Comparator<Integer>(){ public int compare(Integer a, Integer b) { return b - a;// 大根堆 } }); int[] ans = new int[nums.length - k + 1]; for (int i = 0; i < k - 1; i++) { heap.offer(nums[i]); } for (int i = 0; i + k <= nums.length; i++) { heap.offer(nums[i + k - 1]); ans[i] = heap.peek(); heap.remove(nums[i]); } return ans; } }
第二搏
显然,在堆中查找并删除元素是非常耗时的!
考虑要删除的元素是指滑动窗口第一个值,要么根据值来删除(同上,采用remove),要么根据位置来删除。
若堆顶元素的位置不在滑动区间范围内,则将其移除。
因此就需要额外存储元素的位置。
第三搏
优先队列的作用主要是为了获得滑动窗口内的最大值,然而若只是想获得窗口内最大值的话,维持一个普通队列就可以了。
- 当向队尾插入一个元素时,只需要将队列中小于等于该元素的值从后向前依次弹出即可;
- 若队头元素不属于滑动区间范围内,则从前向后弹出即可;
这样队头的元素一定是最大,且最新的(位于滑动窗口右侧,相较于左侧淘汰的晚些);
可以从上面看出,队列需要支持队头和队尾操作,因此我们采用双端队列。
此外,为了方便的判断元素的位置,队列中存放的值应该为数组中元素对应的下标(有下标后就可以很方便的获得对应的值)。因此队列中存放的值(数组下标)总保持递增的顺序,也就是通常所说的单调队列。
这篇关于LeetCode_Queue_239. Sliding Window Maximum 滑动窗口最大值【优先队列,单调队列】【java】【中等】的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-01一个基于注解驱动的可视化的DDD架构-超越COLA的设计
- 2025-01-01PlantUML 时序图 基本例子
- 2025-01-01plantuml 信号时序图
- 2025-01-01聊聊springboot项目如何优雅进行数据校验
- 2024-12-31自由职业者效率提升指南:3个时间管理技巧搞定多个项目
- 2024-12-31适用于咨询行业的项目管理工具:提升跨团队协作和工作效率的最佳选择
- 2024-12-31高效协作的未来:2024年实时文档工具深度解析
- 2024-12-31商务谈判者的利器!哪 6 款办公软件能提升春节合作成功率?
- 2024-12-31小团队如何选择最实用的项目管理工具?高效协作与任务追踪指南
- 2024-12-31数据赋能,智慧养老:看板软件如何重塑养老服务生态