滑动窗口的最大值
给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。
样例:
输入:数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3
输入:一共存在6个滑动窗口,它们的最大值分别为{4,4,6,6,6,5}
解题思路
蛮力法
扫描每个滑动窗口的所有数字并找出其中的最大值。如果滑动窗口为k,则需要O(k)O(k)O(k)时间才能找出滑动窗口里的最大值。对于长度为n的输入数组,这种算法的总时间复杂度是O(nk)O(nk)O(nk).
双向队列
定义一个双向队列来存储滑窗的最大值,所谓双向队列,就是同时具有队列和栈的性质的数据结构。在Python中,再不调用其他模块的情况下,也可以用list来实现。
结合例子来进行说明:
输入:数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3
第一步插入首个元素2,此时滑窗为[2],我们将元素的下标存进双向队列[0](为什么是下标等会再说);
第二步插入元素3,因为3比2大,2不可能是滑窗的最大值,因此弹出2的下标,此时滑窗为[2,3],队列为[1];
第三步插入元素4,同理4比3大,弹出3,此时滑窗为[2,3,4](已经达到滑窗本身k的大小),队列为[2];
第四步插入元素2,2虽然比4小,但4滑出窗口后,2是有可能成为最大值的,先插入队列,此时滑窗为[3,4,2],队列为[2,3];
第五步插入元素6, 6比2,4都大,因此都弹出,此时滑窗为[4,2,6],队列为[4];
第六步插入元素2, 2虽然比6小,但先考虑保留,此时滑窗为[2,6,2],队列为[4,5];
第七步插入元素5, 5也比6小,考虑保留,此时滑窗为[6,2,5],队列为[4,5,6];
第八步插入元素1, 这里要注意6已经移出滑窗了,因此我们要先将6的下标4弹出,此时滑窗为[2,5,1],队列为[6,7].
为什么我们保存下标,而不是元素本身?
因为还要考虑移出滑窗的情况,必须保存元素的下标,才能判断元素是不是移出滑窗了。
关于滑窗的最大值
因为我们是从数组的开头开始遍历,因此要注意,到第k-1个元素开始才会有滑窗的最大值,
比如上例中,滑窗的大小为3,就要遍历到nums[2],才会有最大值;
滑窗的最大值都位于双向队列的首位。
算法的时间复杂度为O(n)O(n)O(n).
class Solution(object):
def maxInWindows(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
if not nums or k <= 0: return None
if k == 1: return nums
deque = [0]
res = []
for i in range(1,len(nums)):
while deque and nums[deque [-1]] <= nums[i]:
deque .pop(-1)
if deque and deque [0] <= i - k:
deque .pop(0)
deque .append(i)
if i >= k - 1:
res.append(nums[deque [0]])
return res