赞
踩
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例 1:
输入: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
示例 2:
输入:nums = [1], k = 1
输出:[1]
示例 3:
输入:nums = [1,-1], k = 1
输出:[1,-1]
示例 4:
输入:nums = [9,11], k = 2
输出:[11]
解决滑动窗口问题一般有三种方法:
1.常规思路:暴力求解——N(nk)
时间复杂度较高,每个元素要被遍历k次
2.增减维护一个优先队列(最大堆)——N(nlogk)
给予一个完全二叉树来实现创库华东,队列入队一次(logk)出队指定元素一次(logk)
减少了重复判断,但是每次出入队还是较为复杂
3.通过单调Deque双端队列:——N(n)
这里我们可以参考一个篮球队长模型(不理解可以跳过):
从入学到毕业 高三队长,高一仍有机会, 高一队长,则高二高三则没有机会(直接抛弃)
实现步骤:
第一步,头部出队,清理超范围
第二步,移除尾部,在当前值前面的还小于当前值的元素
第三步,尾部入队,尾部范围正确
第四步,返回头部一一当前窗口最大值
即将入队的3大于对位的1,将1抛弃,并且入队3
3不小于即将入队的-1,则直接入队-1
同理-3入队(队首无出队:索引最小的元素此时还未超出窗口的最小范围)
将超出下限的3出队,在5入队前比较与-1,-3的大小,将其全部出队
继续将3入队(5 > 3不进行出队)
3和5都小于6,在6入队前先将3和5出队
最后6出队,7入队
单调的含义即,头部大尾部小,所以每次返回窗口的第一个元素即可。
代码如下:
python:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if not nums:return []
window, res = [], [] #window存储窗口中元素的下标,res存储结果
for i, x in enumerate(nums):
#当window中第一个下标溢出时,将其踢出队列(左侧)
if i >= k and window[0] <= i - k:
window.pop(0)
#加入下一个元素x前,将队尾小于x的元素出队(右侧)
while window and nums[window[-1]] <= x:
window.pop()
window.append(i)
if i >= k - 1:
res.append(nums[window[0]])
return res
c++:
class Solution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k) { if(k==0)return {}; vector<int>res; deque<size_t>window; /*Init K integers in the list*/ for (size_t i = 0; i < k; i++) { while (!window.empty() && nums[i] > nums[window.back()]) { window.pop_back(); } window.push_back(i); } res.push_back(nums[window.front()]); /*End of initialization*/ for (size_t i = k; i < nums.size(); i++) { if (!window.empty() && window.front() <= i - k) { window.pop_front(); } while (!window.empty() && nums[i] > nums[window.back()]) { window.pop_back(); } window.push_back(i); res.push_back(nums[window.front()]); } return res; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。