Sliding Window Maximum

52 篇文章 0 订阅
6 篇文章 0 订阅

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.

思路:发现单调栈的性质,因为如果4,8 那么,4是没必要存的,那么stack里面存单调当前的最大值,如果发现后面进来的元素比末尾的大,把末尾的一直踢走,也就是踢走4,一直踢到没有比他大为止,那么就是个单调递减的序列,但是这个窗口还在滑动,也就是前面的值要踢走,那么前面要出,后面要进,还要后面还要动态弹出去,前后都出去的数据结构就是deque。O(N)

8,4为什么要keep 4,也就是4是最大值的candidate,因为8走了,4可能成大王;

所有这种k window的题目,可以首先收集 [0 ~ k -2] 的元素,然后从第k个开始,开始计算;

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums == null || nums.length == 0) {
            return nums;
        }
        Deque<Integer> deque = new ArrayDeque<Integer>();
        int n = nums.length;
        int[] res = new int[n - k + 1];
        int index = 0;
        for(int i = 0; i < nums.length; i++) {
            if(i < k - 1) {
                inqueue(deque, nums, i);
            } else {
                // i >= k - 1;
                inqueue(deque, nums, i);
                res[index++] = nums[deque.peekFirst()];
                dequeue(deque, nums, i - k + 1);
            }
        }
        return res;
    }
    
    private void inqueue(Deque<Integer> deque, int[] nums, int pos) {
        while(!deque.isEmpty() && nums[deque.peekLast()] <= nums[pos]) {
            deque.pollLast();
        }
        deque.addLast(pos);
    }
    
    private void dequeue(Deque<Integer> deque, int[] nums, int pos) {
        if(!deque.isEmpty() && deque.peekFirst() == pos) {
            deque.pollFirst();
        }
    }
}

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

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums == null || nums.length == 0 || k < 0) {
            return new int[0];
        }
        PriorityQueue<Integer> pq 
            = new PriorityQueue<Integer>(k, Collections.reverseOrder());
        int[] res = new int[nums.length - k + 1];
        int index = 0;
        for(int i = 0; i < nums.length; i++) {
            pq.offer(nums[i]);
            if(pq.size() == k) {
                res[index++] = pq.peek();
                pq.remove(nums[i - k + 1]);
            }
        }
        return res;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值