Sliding Window Maximum

来源:互联网 发布:硕鼠 mac 怎么用 编辑:程序博客网 时间:2024/06/06 14:06

Given an array 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 thek numbers in the window. Each time the sliding window moves right by one position.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

Window position                Max---------------               -----[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

Therefore, return the max sliding window as [3,3,5,5,6,7].

Note: 
You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array.

Follow up:
Could you solve it in linear time?

Hint:

  1. How about using a data structure such as deque (double-ended queue)?
  2. The queue size need not be the same as the window’s size.
  3. Remove redundant elements and the queue should store only elements that need to be considered.

思路:题目已经提示用Deque来实现存储不必要的数,也就是窗口里面并不是所有的数都需要。这题有点类似用dequeue实现stack的思想。也就是,dequeue里面存的是到目前为止sliding window里面,从大到小的数的index。如何实现从大到小,就是每次加进去的时候,尝试的往前移动,也就是把队列尾部的元素全部打掉,能打到哪里就打到哪里,这样自己就是在这个队列里面应有的位置,然后如果队列的头超出了范围就把头部踢掉。(这一部分用index来计算,这里index的计算也是个考点,有点复杂,自己在纸上画画会比较清楚)。然后每次都存dequeue的头部也就是最大值了。这样窗口扫描一遍,也就是O(n).

实在不懂了看这个:https://segmentfault.com/a/1190000003903509

public class Solution {    public int[] maxSlidingWindow(int[] nums, int k) {        if(nums == null || nums.length == 0 || k<=0) return nums;        int[] res = new int[nums.length-k+1];        Deque<Integer> queue = new LinkedList<Integer>();        for(int i=0; i<nums.length; i++){            // 每当新数进来时,如果发现队列头部的数的下标,是窗口最左边数的下标,则扔掉            if(queue.size()>0 && queue.getFirst() == i-k){                queue.poll();            }            // 把队列尾部所有比新数小的都扔掉,保证队列是降序的            while(queue.size() > 0 && nums[queue.getLast()]<nums[i]){                queue.removeLast();            }            // 加入新数             queue.addLast(i);            // 队列头部就是该窗口内第一大的.            if(i+1 >=k){                res[i-k+1] = nums[queue.getFirst()];            }        }        return res;    }}

思路2:这题也可以用pq来做。nlogk. 维护一个大小为K的最大堆,依此维护一个大小为K的窗口,每次读入一个新数,都把堆中窗口最左边的数扔掉,再把新数加入堆中,这样堆顶就是这个窗口内最大的值.

public class Solution {     public int[] maxSlidingWindow(int[] nums, int k) {         if(nums == null || nums.length == 0 || k<=0) return nums;         int[] res = new int[nums.length-k+1];         PriorityQueue<Integer> pq = new PriorityQueue(k, new Comparator<Integer>(){            @Override            public int compare(Integer a, Integer b){                return b.intValue() - a.intValue();            }         });                  int index = 0;         for(int i=0; i<nums.length; i++){             pq.add(nums[i]);             while(pq.size() >k){                 pq.remove(nums[i-k]);             }             if(pq.size() == k){                 res[index] = pq.peek();                 index++;             }         }         return res;     } }


0 0
原创粉丝点击