单调队列
分析
滑动窗口并不对应单调队列
滑动窗口问题可以用双指针 和 队列 两种方式实现
单调队列只是针对这个窗口里的某个性质 将不必要的元素舍去
从而能在O(1)的时间内找到这个最值
一般也就两个场景
找窗口的最小值
void get_min(int a[],int b[],int tot,int k)
{
int hh=0,tt=-1;
for(int i=0;i<tot;i++)
{
if(hh<=tt && i-q[hh]>=k)
hh++;
//求最小 递增区间 若出现向下 出队
while(hh<=tt && a[i]<=a[q[tt]])
tt--;
q[++tt]=i;
//当前区间的最大值为队头
b[i] = a[q[hh]];
}
}
找窗口的最大值
void get_max(int a[],int b[],int tot,int k)
{
int hh=0,tt=-1;
for(int i=0;i<tot;i++)
{
if(hh<=tt && i-q[hh]>=k)
hh++;
//求最大 递减区间 若出现向上 出队
while(hh<=tt && a[i]>=a[q[tt]])
tt--;
q[++tt]=i;
//当前区间的最大值为队头
b[i] = a[q[hh]];
}
}
另外注意分析 我们要的答案是在插入新元素之前还是在插入新元素之后
void get_max/* min */(int a[],int b[],int tot,int k)
{
int hh=0,tt=-1;
for(int i=0;i<tot;i++)
{
if(hh<=tt && i-q[hh]>=k) //这里一定有等于 因为要腾空间放新元素 满了就得出去
hh++;
//具体操作也可能放在这里
//这是把新元素放进去之前就找答案
//最大最小只要改这里 最大应该是递减 最小应该是递增 出现异常就出队
//另外注意代入情景看等于是否影响结果 一般是也剔除 除非是要什么最左边的 才考虑去=
while(hh<=tt && a[i]>/* < */=a[q[tt]])
tt--;
q[++tt]=i;
//具体操作可能放在这里
//这是把新元素放进去后再找答案
}
}
stl版
class Solution {
public:
vector<int> maxInWindows/* minInWindows */(vector<int>& nums, int k) {
vector<int> res;
deque<int> q;
for(int i=0;i<nums.size();i++)
{
if(!q.empty() && i-q.front()>=k)
q.pop_front();
//具体操作 情况2
//……
while(!q.empty() && nums[i]>= /* <= */ nums[q.back()])
q.pop_back();
q.push_back(i);
//具体操作 情况1
//……
if(i>=k-1)
res.push_back(nums[q.front()]);
}
return res;
}
};
题目
更多题目:
- 剑指 Offer 59 - II. 队列的最大值
- 滑动窗口最大值
- 剑指 Offer 59 - I. 滑动窗口的最大值
- 绝对差不超过限制的最长连续子数组
- 跳跃游戏 VI
- 带限制的子序列和
- 环形子数组的最大和
- 和至少为 K 的最短子数组
- 分割数组的最大值
💬 评论