天天看点

leetcode -- Sliding Window Maximum -- 重点为什么要用deque呢?

https://leetcode.com/problems/sliding-window-maximum/

思路见code,参考http://www.jianshu.com/p/7662caf4f39c

http://bookshadow.com/weblog/2015/07/18/leetcode-sliding-window-maximum/

为什么要用deque呢?

这里是滑动窗口,每次滑动,都会有值从右边进,然后又有值从左边出。所以用双向队列就很好。维护队头元素为当前窗口的最大值.因为向右滑动的时候,要从左边remove一个元素,如果这个元素是上一个window的最大值,那么就要更新这个最大值,这个新的最大值肯定出现在旧的最大值的后面,所以,这里用deque,队头为最大元素,下一个元素为这个最大元素后面的最大元素。。。

思路:

遍历数组nums,使用双端队列deque维护滑动窗口内有可能成为最大值元素的数组下标

由于数组中的每一个元素至多只会入队、出队一次,因此均摊时间复杂度为O(n)

记当前下标为i,则滑动窗口的有效下标范围为[i - (k - ), i]

若deque中的元素下标< i - (k - ),则将其从队头弹出,deque中的元素按照下标递增顺序从队尾入队。

这样就确保deque中的数组下标范围为[i - (k - ), i],满足滑动窗口的要求。

当下标i从队尾入队时,顺次弹出队列尾部不大于nums[i]的数组下标(这些被弹出的元素由于新元素的加入而变得没有意义)

deque的队头元素即为当前滑动窗口的最大值
           

这里deque就是维护一个区间内第一大,第二大,。。。的结构,最大的放在队头

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[-] < nums[i]:#等于可以跳出了
                d.pop()
            d.append(nums[i])
            if i > k -  and d[] == nums[i - k]:
            '''
            这里i > k - 1,就是第一个windows已经建好了,开始滑动。d[0] == nums[i - k], 本来的windows index是从[i - (k-1), i],i现在往前走了一步,现在区间变成了[i-k, i],window长度为k+1, 要popleft掉第一个i-k元素。新的队头元素就是新的max
            '''
                d.popleft()
            if i >= k - :#窗口开始滑动之后deque的第一个值就是结果。
                res.append(d[])

        return res