什么情况下我们需要单调栈?
单调栈适合处理依赖序列单调性质的问题,
单调栈在某种意义上是在线算法,因为是动态增删元素。
给定一个序列,在该序列中左边比它小且离它最近的数在哪?
具体应用:单调栈
暴力做法:
for(int i=0;i<n;i++)
for(int j=i;j>=0;j--)
if(a[j]<a[i]) cout<
单调栈怎么实现?
优化思路:
如果存在a[x]>=a[y]且x<y
则a[x]显然不是y左边第一个比它小的数,出栈
依此规则,我们将获得一个严格单调的栈
栈顶即是y对应的答案,离y最近且比y小
如果不单调,我们将破坏单调性的元素
(没用的元素,不可能输出的元素,既较远又较大的元素)出栈
#include<iostream>
using namespace std;
const int N=100010;
int stk[N],tt=0;
int main()
{
int n;
cin>>n;
while(n--)
{
int x;
cin>>x;
while(tt&stk[tt]>=x) tt--;//该循环使整个栈内元素单调递增
if(!tt) printf("-1");
else printf("%d",stk[tt]);
stk[tt++]=x;
}
return 0;
}
单调栈例题:直方图最大矩形的面积
解题思路:
枚举某一根柱子,将其高度固定为矩形的高度h,随后两边延伸,寻找高度比h小的柱子,也就是矩形的边界,当左右两边界宽度为w,那么对应的矩形面积为 w * h。
优化思路:关键在于找到左右边界的柱子
也就是离该柱子最近且较小的柱子
所以我们可以根据栈先进后出的特性,遍历存储有可能成为边界的柱子的下标,形成一个自底向上递增的单调栈
什么情况下我们需要单调队列?
基于单调栈的一个扩展,当单调栈的栈底元素可以弹出的时候,单调栈即可转化单调队列。 单调队列可以在 O ( 1 ) 的时间内,获取队首队尾区间的最值,因此单调的区间的最大用处,也在于获取区间的最值上。
具体应用:滑动窗口(经典模型)
单调队列怎么写?
解决思路:
窗口采用队列来维护
每次操作包括入队和出队
暴力做法:遍历队列(窗口)内的所有元素
优化思路:类似单调栈
寻找队列(窗口)中没有用的元素
用数组模拟的队列比stl更快
#include<iostream>
using namespace std;
const int N=1000010;
int q[N],a[N];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int hh=0,tt=-1;
for(int i=0;i<n;i++)
{
if(i-k+1>q[hh]) hh++;//队头向后移动一位
while(hh<=tt&&a[q[tt]]>=a[i]) tt--;//使队列递增
q[++tt]=i;
if(i+1>=k) printf("%d ",a[q[hh]]);//输出队头,即最小值
}
cout<<endl;
hh=0,tt=-1;
for(int i=0;i<n;i++)
{
if(i-k+1>q[hh]) hh++;
while(hh<=tt&&a[q[tt]]<=a[i]) tt--;
q[++tt]=i;
if(i+1>=k) printf("%d ",a[q[hh]]);
}
return 0;
}
单调队列例题:滑动窗口的最大值
维护窗口的长队,队头是否需要出队
维护队列的单调性,队尾是否需要出队
输出队头,即最值
class Solution {
public:
vector<int> maxInWindows(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();
while(!q.empty()&&nums[q.back()]<nums[i])//维护队列单调性
q.pop_back();
q.push_back(i);
if(i >= k-1){
res.push_back(nums[q.front()]);//取队头作为窗口最大元素
}
}
return res;
}
};
文章介绍了单调栈和单调队列的概念和应用场景。单调栈常用于处理序列中依赖单调性质的问题,例如找到序列中每个元素左边比它小的最近元素。而单调队列是在单调栈基础上的扩展,适用于滑动窗口最大值等问题,能在O(1)时间内获取区间最值。文章通过代码示例展示了如何实现这两种数据结构并解决相关问题。
1008

被折叠的 条评论
为什么被折叠?



