LeetCode 239 [Sliding Window Maximum]

原题

给出一个可能包含重复的整数数组,和一个大小为 k 的滑动窗口, 从左到右在数组中滑动这个窗口,找到数组中每个窗口内的最大值。

给出数组 [1,2,7,7,8], 滑动窗口大小为 k = 3. 返回 [7,7,8].
最开始,窗口的状态如下:
[1, 2 ,7 ,7 , 8], 最大值为 7;
然后窗口向右移动一位:
[1, 2, 7, 7, 8], 最大值为 7;
最后窗口再向右移动一位:
[1, 2, 7, 7, 8], 最大值为 8.

解题思路

  • 方法一:最直观的,每次从起点i遍历一遍窗口长度j = i, i + k,找最大值,两层for循环,时间复杂度O(n * k)
  • 方法二:维护一个hash heap,每次移动,加入右边元素O(logk),减去左边元素O(logk),返回maxheap中的最大值O(1),时间复杂度为O(n * logk)
  • 使用Deque,维护一个递减的deque,时间复杂度为O(n)
已知 [1, 2, 7, 3, 8, 5, 3, 2]
[1], 2进入, 2 > 1 弹出1
[2], 7进入, 7 > 2 弹出2
[7], 第一个窗口最大值为7,3进入,3 < 7
[7, 3], 第二个窗口最大值为7,8进入, 8 > 3 弹出3
[7], 8 > 7, 弹出7 
[8], 第三个窗口最大值为8

为什么要用deque呢?注意这种情况

当前为[9, 8, 7], 6进入,6 < 7, 6进入
[9, 8, 7, 6] 但是对K=3的窗口,必须要弹出9,这步就要用到deque
  • Python中使用deque, 和list的API类似,多了popleft, appendleft, extendleft
import collections
d = collections.deque()
d.extend([1, 2, 3])
d.pop() # 3
d.popleft() # 1
d.append() # [2, 10]
d.appendleft() # [20, 2, 10]
d[0] # peek at leftmost item
d[-1] # peek at rightmost item
if d:
    # d is not empty
else:
    # d is empty

完整代码

import collections

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        res = []
        d = collections.deque()
        for i in range(len(nums)):
            while d and d[-1] < nums[i]:
                d.pop()
            d.append(nums[i])
            if i > k - 1 and d[0] == nums[i - k]:
                d.popleft()
            if i >= k - 1:
                res.append(d[0])
                
        return res

你可能感兴趣的:(LeetCode 239 [Sliding Window Maximum])