滑動窗口的最大值
題目描述
給定一個數組和滑動窗口的大小,找出所有滑動窗口里數值的最大值。例如,如果輸入數組{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]}。
思路
- 我們可以用一個隊列來存儲每個窗口的數,然后選出最大的,不過這樣代價有點大
- 其實不必每個窗口的每個數都存下來,我們用一個雙向隊列deque來存儲,注意:我們在這存的是數組元素的索引
- 如果新來的值比隊列尾部的數小,那就追加到后面,因為它可能在前面的最大值划出窗口后成為最大值
- 如果新來的值比尾部的大,那就刪掉尾部(因為有更大的在后面,所以它不會成為最大值,划出也是它先划出,不影響最大值),再追加到后面,循環下去直到小於
- 如果追加的值比的索引跟隊列頭部的值的索引超過窗口大小,那就刪掉頭部的值
- 其實這樣每次隊列的頭都是最大的那個
代碼
import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; public class Solution { public ArrayList<Integer> maxInWindows(int [] num, int size) { ArrayList<Integer> result = new ArrayList<Integer>(); if (num == null || num.length < size || size == 0) { return result; } Deque<Integer> deque = new ArrayDeque<Integer>(); for (int i = 0; i < num.length; i++) { if (!deque.isEmpty() && (i - deque.peekFirst()) == size) { // 如果隊列頭部的元素已經超出滑動窗口的范圍,就將頭部元素退出 deque.pollFirst(); } while (!deque.isEmpty() && num[i] >= num[deque.peekLast()]) { // 如果新來的元素比隊列最后一個元素大,則將最后一個元素退出 deque.pollLast(); } deque.offer(i); if (i >= (size - 1)) { // 如果遍歷的元素已經達到一個滑動窗口的大小,就開始提取窗口的最大值了 result.add(num[deque.peekFirst()]); } } return result; } }