首先窗口向右滑动的过程就是将窗口最左侧的元素删除,同时在窗口的最右侧添加一个新的元素,这就要用到双端队列,然后找双端队列中的最大元素。
那剩下就是如何找到滑动窗口中的最大值。
那我们就可以只在队列中保留可能成为窗口最大元素的元素,去掉不可能成为窗口中最大元素的元素。
想象一下,如果要进来的是个值大的元素,那一定会比之前早进去的值小的元素晚离开队列,而且值大的元素在,都没值小的元素啥事,所以值小的元素直接弹出队列即可。
这样队列里其实维护的一个单调递减的单调队列。
deque双向队列 出口是front(左)入口是back(右) ,双端均可以自定义进出
dq.pop_front()左侧弹出
dq.pop_back()右侧弹出
class Solution {
class MyQueue{
public:
deque<int> dq;
void push(int value){
while(!dq.empty() && value > dq.back()){
dq.pop_back();
}
dq.push_back(value);
}
void pop(int value){
if(!dq.empty() && value == dq.front()){
dq.pop_front();
}
}
int max(){
return dq.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int> result;
for(int i = 0; i<k; i++){
que.push(nums[i]);
}
result.push_back(que.max());
for(int i=k;i<nums.size();i++){
que.pop(nums[i-k]);
que.push(nums[i]);
result.push_back(que.max());
}
return result;
}
};
先定义一种自己的deque规则包括push加入元素、pop弹出元素、max返回最大值
每次滑动,删除离开窗口的值(可能已经弹出了,那在自定义的在自定义的pop里就无需处理),加入新元素时,比新元素小的队列值右侧弹出,比新元素大的保持在新元素左侧。保证队列一直是单调递减,最左边获取最大值。
注意不要丢掉类的访问修饰符!!
以及以下这两个变量关系解释
单调队列正式登场!| LeetCode:239. 滑动窗口最大值_哔哩哔哩_bilibili
在代码中,`deque<int> que;` 和 `MyQueue que;` 是两个不同的对象,但它们之间存在一定的关系。让我们逐步分析它们的关系和作用。
### 1. `deque<int> que;`
- `deque<int> que;` 是 `MyQueue` 类中的一个成员变量,类型为 `deque<int>`(双端队列)。
- 这个 `deque` 用于实现单调队列的功能,即在 `MyQueue` 类中维护一个从大到小的单调队列。
- `deque` 提供了在两端进行高效插入和删除操作的能力,因此非常适合用来实现单调队列。### 2. `MyQueue que;`
- `MyQueue que;` 是 `Solution` 类中的一个成员变量,类型为 `MyQueue`。
- 这个 `que` 是 `MyQueue` 类的一个实例,用于在 `maxSlidingWindow` 函数中维护滑动窗口的最大值。
- `MyQueue` 类封装了对 `deque<int> que;` 的操作,提供了 `pop`、`push` 和 `front` 等方法,用于维护单调队列的性质。### 3. 关系
- `deque<int> que;` 是 `MyQueue` 类内部用来存储数据的容器,而 `MyQueue que;` 是 `Solution` 类中用来管理滑动窗口最大值的工具。
- 当你在 `maxSlidingWindow` 函数中调用 `que.push(nums[i]);` 或 `que.pop(nums[i - k]);` 时,实际上是在操作 `MyQueue` 类中的 `deque<int> que;`。
- `MyQueue` 类通过封装 `deque<int> que;` 并提供相应的操作接口,简化了在滑动窗口中维护最大值的过程。### 4. 代码执行流程
1. 在 `maxSlidingWindow` 函数中,首先创建一个 `MyQueue` 的实例 `que`。
2. 然后,将前 `k` 个元素通过 `que.push(nums[i]);` 加入到 `MyQueue` 中的 `deque<int> que;` 中。
3. 接着,通过 `que.front();` 获取当前窗口的最大值,并将其加入到结果集 `result` 中。
4. 之后,滑动窗口向右移动,每次移除最左边的元素(通过 `que.pop(nums[i - k]);`),并加入新的元素(通过 `que.push(nums[i]);`),同时记录当前窗口的最大值。### 总结
- `deque<int> que;` 是 `MyQueue` 类内部用来存储数据的双端队列。
- `MyQueue que;` 是 `Solution` 类中用来管理滑动窗口最大值的工具,它通过操作内部的 `deque<int> que;` 来实现单调队列的功能。
- 两者之间的关系是:`MyQueue` 类封装了 `deque<int> que;`,并提供了对外的接口来维护滑动窗口的最大值。
如果不进行封装类、类的方法
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> dq;
vector<int> result;
for(int i = 0; i < k; i++){
while(!dq.empty() && nums[i] > dq.back()){
dq.pop_back();
}
dq.push_back(nums[i]);
}
result.push_back(dq.front());
for(int i = k; i < nums.size(); i++){
if(!dq.empty() && dq.front() == nums[i-k]){
dq.pop_front();
}
while(!dq.empty() && nums[i] > dq.back()){
dq.pop_back();
}
dq.push_back(nums[i]);
result.push_back(dq.front());
}
return result;
}
};
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> dq; // 单调队列,存储元素的值
vector<int> result;
for (int i = 0; i < nums.size(); i++) {
// 移除队列中不在当前窗口的元素
if (!dq.empty()&& i >= k && dq.front() == nums[i - k]) {
dq.pop_front();
}
// 维护单调递减队列
while (!dq.empty() && nums[i] > dq.back()) {
dq.pop_back();
}
// 将当前元素加入队列
dq.push_back(nums[i]);
// 当窗口大小达到 k 时,记录最大值
if (i >= k - 1) {
result.push_back(dq.front());
}
}
return result;
}
};