Hard-题目15:239. Sliding Window Maximum

题目原文:
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 the k 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].
题目大意:
给出一个数组和一个k长度的滑动窗口,把滑动窗口从数组开头滑到结尾,求每个滑动窗口内子数组的最大值,组成一个新数组并返回。
题目分析:
朴素解法是暴力枚举每个滑动窗口的最大值,时间复杂度是O(nk),虽然也能ac,但一个hard难度的题不可能只要求到这步。
根据hint,考虑用双端队列,维持队列长度小于等于k,且队头永远为滑动窗口最大值,队列后面跟的是可能成为最大值的候选解。每次加入一个元素,先看队头元素的下标是否已经在滑动窗口之外,如果在则出队,接下来判断这个元素是否大于队尾的值,如果大于则从队尾一直弹出(因为有了这个更大的数,前面的数在往右滑的过程中不可能是解),每次记录下队头的值,即为当前滑动窗口的最大值。
那么还有一个问题,如何知道队头是否滑到了窗口外面呢?答案是,我们的deque只要存的是下标就可以了。因为队列的操作全都是常数时间的,这样的时间复杂度就降到了O(n).
源码:(language:java)

public class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length==0)
            return new int[0];
        int[] window = new int[nums.length-k+1];
        int j=0;
        Deque<Integer> deque = new LinkedList<>();
        for(int i = 0;i<nums.length;i++) {
            while (!deque.isEmpty() && nums[deque.getLast()] < nums[i]) {
                deque.removeLast();
            }
            deque.addLast(i);
            if(deque.getFirst() == i-k)
                deque.removeFirst();
            if(i>=k-1)
                window[j++] = nums[deque.getFirst()];
        }
        return window;
    }
}

成绩:
29ms,beats 62.07%,众数31ms,9.54%
Cmershen的碎碎念:
这道题在Leetcode里面算是难题了,且对面试来说算是比较困难的一题,Leetcode的国内山寨版Lintcode的难度评分中将其评为Very Hard难度(lintcode里面very hard难度只有两题,另一题是涉及到线段树的skyline problem),足见此题对普通面试者的难度。
此外discuss中还有一个仅4ms的解法,有机会研读一下。

你可能感兴趣的:(Hard-题目15:239. Sliding Window Maximum)