一、题目
239. 滑动窗口最大值
剑指 Offer 59 - I. 滑动窗口的最大值
二、分析
采用双端单调递减队列,保证队列中从大到小的顺序,为了方便,队列中只存储数组下标。
- 当队头元素超出窗口,则队友元素出队。
- 当新元素比队尾元素大,循环出队,保持队列的单调减。
nums = [1,3,-1,-3,5,3,6,7], k = 3
滑动窗口的位置 队列
--------------- -----
[1 3 -1] -3 5 3 6 7 3 -1
1 [3 -1 -3] 5 3 6 7 3 -1 -3
1 3 [-1 -3 5] 3 6 7 5 //-3 -1 3依次从队尾出队,保持单调减
1 3 -1 [-3 5 3] 6 7 5 3
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
如果,是下面这个例子:
nums = [1,3,-1,-3,-4,3,6,7], k = 3
滑动窗口的位置 队列
--------------- -----
[1 3 -1] -3 -4 3 6 7 3 -1
1 [3 -1 -3] -4 3 6 7 3 -1 -3
1 3 [-1 -3 -4] 3 6 7 -1 -3 -4 //由于3已经超出窗口,从队头出队
1 3 -1 [-3 -4 3] 6 7 3
1 3 -1 -3 [-4 3 6] 7 6
1 3 -1 -3 -4 [3 6 7] 7
三、代码
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n(nums.size());
vector<int> res;
if(n == 0) return res;
if(k == 1) return nums;
int maxFirst = INT_MIN;
int maxIndex = 0;
deque<int> sw; //记录下标
sw.push_back(0);
for(int i = 1; i < n; i ++){
//判断队头有没有超出窗口
if(!sw.empty() && sw.front() <= i-k) sw.pop_front();
// 循环地从队尾删除元素,保证单调减
while(!sw.empty() && nums[sw.back()] < nums[i]){
sw.pop_back();
}
sw.push_back(i);
//开始记录窗口最大值,即队头元素
if(i >= k-1){
res.push_back(nums[sw.front()]);
}
}
return res;
}
};
执行用时:368 ms, 在所有 C++ 提交中击败了67.60%的用户
内存消耗:128.7 MB, 在所有 C++ 提交中击败了24.50%的用户