***239. Sliding Window Maximum 滑动窗口最大值
1. 原始题目
给定一个数组 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
注意:
你可以假设 k 总是有效的,1 ≤ k ≤ 输入数组的大小,且输入数组不为空。
进阶:
你能在线性时间复杂度内解决此题吗?
2. 思路
方法1.暴力法
方法2.最大堆(优先队列)
方法3.队列(核心思路:滑动窗口的最大值总是保存在队列首部,队列里面的数据总是从大到小排列。)
看一下利用队列的做法:针对上面 [1,3,-1,-3,5,3,6,7], 和 k = 3,定义一个队列temp=[]和存放结果的数组res=[]。
begin:
首先1进队,3进队,因为3比1大,此时1应出队,因为3比1大,1就没有机会成为窗口最大值。-1进队(实际我们保存索引)。此时temp=【1,2】,res=[3]。
然后该-3进队了,进队前先看当前队内元素数目小于k,并且对内元素都比它大,所以-3直接进队。此时temp=【1,2,3】,res=[3,3]。
然后该5进队了,进队前发现temp已经有k=3个元素了,那队首就该出去腾位置,然后在比较剩余的元素都比5小,都出对。然后5进队。此时temp=[4],res=[3,3,5]。
然后该3进队了,进队前发现队内元素数目小于k,在比较其他元素都比他大,所以3进队。此时temp=【4,5】,res=[3,3,5,5]。
然后该6进队了,进队前发现队内元素数目小于k,其他元素都比他小!都出去,6近来。此时temp=【6】,res=【3,3,5,5,6】。
然后该7进队了,进队前发现对内元素数目小于k,其他元素都比他小!都出去,7自己进来。此时temp=【7】,res=[3,3,5,5,6,7]。
end
此题最初没有想明白具体流程,导致一直有bug,理清楚上面的思路后就通过了。算法实现步骤如下:
假设我们已经有了一个窗口 [ ],此时我们要将窗口右移,即新的元素要进窗口,此时我们要先做两个判断:
1) 判断窗口内的元素是否已经有k个了,如果=k了,此时应该将队列首元素出队。好,此时起码给我们腾出了空间允许新元素进队(队内的元素最多k个!因为窗口大小就是k)。
2)判断完之后,我们的i+1个新元素要进队了,此时要判断之前队内的元素哪些比他小,小的元素都要出队。
两个判断结束。好,一切都准备就绪了,这个第i+1元素进队,然后将队首的元素存放到结果中。
1 class Solution:
2 def maxSlidingWindow(self, nums, k):
3 if not nums or k<1: return []
4 temp = [] # 临时队列
5 res = [] # 结果存放
6 for i in range(len(nums)):
7
8 if temp and i-temp[0]>=k: # 判断1.是否队列的元素数目已经有k个了,若是则队首出,腾位置
9 temp.pop(0)
10
11 temp = [k for k in temp if nums[k]>nums[i]] # 判断2.当前i个元素加入后,是否队内元素没有递减排序
12
13 temp.append(i) # 判断完成,索引i进队
14 if i>=k-1:
15 res.append(nums[temp[0]]) # 保存队首元素作为当前窗口最大值
16
17 return res

浙公网安备 33010602011771号