一个滑动窗口可以看成一个队列,当窗口滑动时,处于窗口的第一个数字被删除,同时在窗口的末尾添加一个新的数字,这符合队列“先进先出”。
思路1:暴力法。时间复杂度为O(nk)
思路2:增减维护一个优先队列。时间复杂度O(n logk)
思路3:通过单调Deque双端队列。Deque里头最大,尾最小。注意Deque里存的是index,不是值。 (时间复杂度O(n),每个下标最多进一次,出一次。)
步骤:头尾尾头
import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; public class Solution { public ArrayList<Integer> maxInWindows(int [] num, int size) { ArrayList<Integer> list = new ArrayList<>(); if (num == null || size < 1 || num.length < size) return list; // 双端队列,deque里存的是数组的index,不是数组的值 Deque<Integer> deque = new LinkedList<>(); for (int i = 0; i < num.length; i++) { //Step1: 头: 移除头部, 保证窗口的长度范围 if (!deque.isEmpty() && (i - deque.getFirst()) >= size){ //这个条件也可以换成 deque.getFirst() < (i - (size - 1)) deque.removeFirst(); } //Step2: 尾: 移除尾部小于当前值的元素, 去除不可能的元素 while (!deque.isEmpty() && num[i] >= num[deque.getLast()]){ deque.removeLast(); } //Step3: 尾部加入, 滑动窗口向右扩充 deque.addLast(i); //Step4: 头, 从头部返回极大值 if (i >= size - 1){ list.add(num[deque.getFirst()]); //list.add(num[deque.peekFirst()]); //所有的dq.getFirst()也可以换为dq.peekFirst() } } return list; } }
参考:
原文:https://www.cnblogs.com/HuangYJ/p/13649894.html