LeetCode 239.滑动窗口最大值

给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。
你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。

进阶:
你能在线性时间复杂度内解决此题吗?

示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:

滑动窗口的位置 最大值


[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

提示:
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
1 <= k <= nums.length

要用O(n)的时间复杂度完成此题,需要用O(1)的时间求出窗口内的最大值。每次移动一个位置,窗口都会在右边增加一个元素并在左边减少一个元素,基础的栈或队列并不能达到要求,这时考虑单调队列这个数据结构。
下面用一个例子解释单调队列:
假设队列的长度为3,开始时Q=[]
加入3,Q=[3]
加入2,Q=[3,2]
加入4,Q=[4]
加入3,Q=[4,3]
加入2,Q=[4,3,2]
加入1,Q=[3,2,1]
可以看出队尾始终是队列中最大的元素。
下面是加入单调队列后的解答:

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        if len(nums) < 2:
            return nums
        q = []
        def push(num):
            while len(q) > 0 and  q[-1] < num:
                q.pop()
            q.append(num)    

        def pop(num):
            if len(q)>0 and q[0]==num:
                q.pop(0)
        def max():
            return q[0]

        ans = []
        for i in range(k):
            num = nums[i]
            push(num)              
        ans.append(max())
        for i in range(k,len(nums)):
            #print(q,i)
            num = nums[i]
            push(num)
            pop(nums[i-k])
            ans.append(max())
        return ans 
原文地址:https://www.cnblogs.com/sandy-t/p/13635048.html