这篇文章主要介绍了LeetCode如何找出队列的最大值和滑动窗口的最大值,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
题目介绍
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5};针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个:{[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
解题思路
方法一:蛮力法
思路
扫描窗口k,得到最大值。对于长度为n的数组,算法时间复杂度O(nk)
显然不是最优解。
方法二:用两个栈实现队列
思路
面试题30中,我们实现过用两个栈实现了队列,可以在O(1)时间得到栈的最大值,也就可以得到队列的最大值。
这样总的时间复杂度O(n)
但是这样的思路写代码,等于同时要写两个题目,面试时间可能不允许。
方法三:双端队列
思路
参考解释:
https://cuijiahua.com/blog/2018/02/basis_64.html
数组的第一个数字是2,把它存入队列中。第二个数字是3,比2大,所以2不可能是滑动窗口中的最大值,因此把2从队列里删除,再把3存入队列中。第三个数字是4,比3大,同样的删3存4。此时滑动窗口中已经有3个数字,而它的最大值4位于队列的头部。
第四个数字2比4小,但是当4滑出之后它还是有可能成为最大值的,所以我们把2存入队列的尾部。下一个数字是6,比4和2都大,删4和2,存6。就这样依次进行,最大值永远位于队列的头部。
但是我们怎样判断滑动窗口是否包括一个数字?应该在队列里存入数字在数组里的下标,而不是数值。当一个数字的下标与当前处理的数字的下标之差大于或者相等于滑动窗口大小时,这个数字已经从窗口中滑出,可以从队列头部把它删除。因此,我们既有可能从头部删除数字,又可能从尾部删除数字,所以要双端队列。
代码
注意点:
-
ArrayDeque的几个API:pollFirst、peekFirst等
-
ArrayDeque保存的是下标
-
最新的数的下标是必定加进去的。
import java.util.ArrayList;
import java.util.ArrayDeque;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
ArrayList<Integer> result = new ArrayList<>();
// 排除特殊情况,窗口的长度为0
if (size==0) return result;
// 滑动窗口最左边数的index
int begin;
// 建立一个双端队列
ArrayDeque<Integer> q = new ArrayDeque<>();
for(int i=0;i<num.length;i++){
// begin是窗口起始位置
begin = i-size+1;
// 队列空,直接加入
if(q.isEmpty())
q.add(i);
// 若队列最左边值已经不在窗口内,直接删除
else if(begin > q.peekFirst())
q.pollFirst();
// 从队尾开始比较,把所有比他小的值丢掉
while((!q.isEmpty()) && num[q.peekLast()] <= num[i])
q.pollLast();
// 随后再把它放进去
q.add(i);
// 若窗口起始位置在数组的0位置上或者之后(窗口是完整大小的),才计算窗口的有效最大值
if(begin>=0){
// 永远是队列最左边最大,加入结果集
result.add(num[q.peekFirst()]);
}
}
return result;
}
}
感谢你能够认真阅读完这篇文章,希望小编分享的“LeetCode如何找出队列的最大值和滑动窗口的最大值”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!
原创文章,作者:kepupublish,如若转载,请注明出处:https://blog.ytso.com/223558.html