1、题目描述
给定一个数组 nums 和滑动窗口的大小 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
2、VS2019上运行
使用单调队列的方法
编程狂想曲的动画演示很清晰
注意:队列q存储的是元素索引值,而不是元素本身,是个双端队列
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
deque<int> q; // 双端队列,这个是用来存储元素索引值的,而不是元素本身
if (!k ||k>n) {//判断一下为空的情况
return {};
}
// 初始化窗口
for (int i = 0; i < k; ++i) {
while (!q.empty() && nums[i] >= nums[q.back()]) {
q.pop_back(); // 保持队列的单调性,从队尾移除较小的元素
}
q.push_back(i); // 将当前元素的索引加入队列
}
vector<int> ans = { nums[q.front()] }; // 存储每个窗口的最大值
// 移动滑动窗口
for (int i = k; i < n; ++i) {
while (!q.empty() && nums[i] >= nums[q.back()]) {
q.pop_back(); // 保持队列的单调性,从队尾移除较小的元素
}
q.push_back(i); // 将当前元素的索引加入队列
while (q.front() <= i - k) {//i-q.front() >=k其实更好理解一些,元素的索引差超过k的值或者等于k的值
q.pop_front(); // 如果队列的头部元素不在当前窗口中,从队头移除
}
ans.push_back(nums[q.front()]); // 将当前窗口的最大值加入结果向量
}
return ans;
}
};
int main() {
Solution solution;
vector<int> nums = { 1, 3, -1, -3, 5, 3, 6, 7 };
int k = 3;
vector<int> result = solution.maxSlidingWindow(nums, k);
for (int i = 0; i < result.size(); ++i) {
cout << result[i] << " ";
}
cout << endl;
return 0;
}
3、队列
- 双端队列:对于这种一端既可以有元素入队,又有元素出队的队列,称之为双向队列
1.push_back(element):将元素添加到队尾。
2.push_front(element):将元素添加到队首。
3.pop_back():从队尾删除一个元素。
4.pop_front():从队首删除一个元素。
5.back():返回队尾元素,不删除。
6.front():返回队首元素,不删除。
7.empty():检查双端队列是否为空。
8.size():返回双端队列中元素的数量。 - 单调队列:从队首到队尾单调递减或递增的队列称之为单调队列。
4、题目思路
- 遍历给定数组中的元素,如果队列不为空且当前考察元素大于等于队尾元素,则将队尾元素移除。直到,队列为空或当前考察元素小于新的队尾元素;
- 当队首元素的下标小于滑动窗口左侧边界left时,表示队首元素已经不再滑动窗口内,因此将其从队首移除。
- 由于数组下标从0开始,因此当窗口右边界right+1大于等于窗口大小k时,意味着窗口形成。此时,队首元素就是该窗口内的最大值。