题目描述
给定一个数组和一个滑动窗口的大小,请找出所有滑动窗口里的最大值。例如,如果输入数组 {2,3,4,6,2,5,1} 及滑动窗口的大小 3,那么一定存在 6 个滑动窗口,它们的最大值分别为 {4,4,6,6,6,5}。
图片说明

解题思路
这个问题最简单的办法自然是暴力求解,每次从一个窗口的起点开始向后遍历k个数字,然后求出最大值,很容易知道这个解法的时间复杂度为O(n^2),但是题目给定的要求是线性的时间复杂度,也就是O(n)。所以这里自然不能用暴力求解。

实际上,我们可以用一个双端队列来存储当前窗口的最大值。我们创建一个双端队列,这里队列中存储的是窗口最大值的下标。如果队列为空,那么就将当前元素的下标添加到队列中。如果队列不为空,那么就有两种情况。如果当前元素比队尾元素所指向的元素还要大,那么当这个元素进入到滑动窗口,队列尾那些比他小的元素所指向的元素,一定不可能是窗口中的最大值,所以就将队尾这些元素删去,直到队尾元素指向的元素比当前的元素大或者相等,然后将当前元素的下标加入队列。如果当前元素比队尾元素所指向的元素要小或者相等,那么就直接将当前元素的下标加入到队列尾。取的时候,只需要取队列头的元素就可以了,因为那就代表着当前窗口的的最大值。取的时候要判断一下,如果队头元素已经是窗口之外了,那么就要将队头出队。否则直接取队头元素就可以了,它就是窗口中最大值对应的下标。文字很多很抽象,用图中的样例来模拟一下好了。

遍历完第一个窗口的时候,队列的元素为1(3)、2(-1),括号中为最大元素,队列元素为元素的下标。所以当前窗口最大值为3
第二个窗口,-3比-1小,所以将3入队,队列元素为1(3)、2(-1)、3(-3),当前窗口最大值为3
第三个窗口,5比队列中所有元素都要大,所以队列中所有元素被清空,队列元素为4(5),当前窗口最大值为5
第四个窗口,队列元素4(5)、5(3)
第五个窗口,队列元素6(6)
.......

所以找出滑动窗口的最大值的过程,实际上就两步工作:

  (1)判断当前的最大值是否过期。

  (2)将读入的数字与 temp 中的元素从后向前依次比较大小,将 temp 中小于读入数字的元素都弹出;如果删除后 temp 的大小还没有达到 size - 1,那么将这个元素压入(删除后 temp 的大小有可能达到 size - 1 嘛?有可能的!因为可能经过比较发现 temp 中没有元素被弹出)。

代码实现

class Solution:
    def maxInWindows(self,num,size):
        if not num:
            return []
        if size > len(num) or size < 1:
            return []
        if size == 1:
            return num
        res = []
        temp = [0]
        for i in range(len(num)):
            if i - temp[0] > size - 1:
                temp.pop(0)
            while len(temp) > 0 and num[i] >= num[temp[-1]]:
                temp.pop()
            if len(temp) < size - 1:
                temp.append(i)
            if i >= size -1:
                res.append(num[temp[0]])
        return res