LeetCode 239.滑动窗口最大值

这道题的题目比较简单,就是在数组中滑动窗口,并找出每次滑动之后窗口中的最大值输出,题目如下所示:
在这里插入图片描述
在上一篇博文数据流中的第K大元素中提到了优先队列,我们可以尝试用优先队列来解答这个问题,首先移动窗口的时候,我们需要把窗口最左边的元素剔除掉,然后将新进入的元素加入到优先队列中,然后再在大顶堆中整理元素位置,代码如下:

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int numLen = nums.length;
        if(nums == null || numLen<k || k<=0){
            return nums;
        }
        int[] res = new int[numLen-k+1];
        
        PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>((a,b)->nums[b]-nums[a]);
        
        for(int i=0;i<k-1;i++){
            maxHeap.offer(i);
        }
        for(int i=k-1;i<numLen;i++){
            maxHeap.offer(i);
            while(maxHeap.peek()<i-(k-1)){
                maxHeap.poll();
            }
            res[i-(k-1)] = nums[maxHeap.peek()];
        }
        return res;
    }
}

这个时候的时间复杂度为: O ( N log K ) O(N \cdot \log K) ,我们可以用双向队列来求解此问题更加简化了时间复杂度,整个过程如下图所示:
在这里插入图片描述
假设有一个数组 [ 1 , 3 , 1 , 3 , 5 , 3 , 6 , 7 ] [1,3, - 1, - 3,5,3,6,7] K = 3 K=3 ,我们用双端队列,每一轮进行移动窗口、维护和输出的动作,每一轮使最大的数在窗口的最左端,如果窗口中左边的元素要小于右边的元素,那么就把左边的元素进行清除维护,最终就能输出结果,图中红色的部分表示窗口的位置。代码如下:

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        if not nums:
            return []
        window, res = [], []
        for i, x in enumerate(nums):
            if i >= k and window[0] <= i - k:
                window.pop(0)
            while window and nums[window[-1]] <= x:
                window.pop()
            window.append(i)
            if i >= k-1:
                res.append(nums[window[0]])
        return res

这个时候整个算法的时间复杂度就为: O ( N ) O(N) ,比上面用优先队列的方法时间复杂度要低很多。这就是滑动窗口中用优先队列和双向队列的解法,希望对大家有所帮助,谢谢。