线性结构 —— 单调栈与单调队列

【单调栈】

1.原理

单调栈,就是栈内元素保持一定单调性(单调递增或单调递减)的栈,即从栈底到栈顶单调递增或递减。

对于单调递增的栈,如果栈为空或入栈元素值大于等于栈顶元素值,则入栈;否则,若入栈会破坏栈的单调性,因此需要将比入栈元素的元素全部出栈。

对于单调递减的栈,如果栈为空或入栈元素值于等于栈顶元素值,则入栈;否则,若入栈会破坏栈的单调性,因此需要将比入栈元素的元素全部出栈。

以下图单调递减的栈为例,从栈顶到栈底初始元素为:6、4、2、1

当插入的元素小于等于栈顶元素时,满足单调递减的条件,可直接加入栈,例如:插入元素 0,可直接加到栈顶

当插入的元素大于等于栈顶元素时,为满足单调递减的性质,需要从栈顶开始,将比入栈元素小的值全部弹出再入栈,例如:插入元素 3,需要先将 1、2 弹出

2.应用

单调栈常用的应用有:

  • 给定一组数,对于某个数,找到从左/右遍历第一个比它小/大的元素的位置
  • 给定一组数,针对每个数,寻找其与其左/右第一个比它小/大的数之间有多少个数
  • 给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大
  • 给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列所有元素和最大

3.实现

1)单调递增栈

 stack<int> S;
 for(int i=1;i<=n;i++){
     while(!S.empty()&&a[S.top()]>a[i]){//栈不为空且栈顶元素大于入栈元素时
        S.pop();//将栈顶大于入栈元素的元素出栈
        ...//更新结果
     }
     S.push(i);//元素入栈
}

2)单调递减栈

 stack<int> S;
 for(int i=1;i<=n;i++){
     while(!S.empty()&&a[S.top()]<a[i]){//栈不为空且栈顶元素小于入栈元素时
        S.pop();//将栈顶小于入栈元素的元素出栈
        ...//更新结果
     }
     S.push(i);//元素入栈
}

【单调队列】

1.原理

单调队列就是从队首到队尾满足单调性的队列,与单调栈极其相似,其基本原理与单调栈相同,只需将单调栈先进后出的性质改为先进先出的性质即可。 

对于单调递增的队列,若队列为空或入队元素 x 于等于队尾元素,则入队;否则,入队会破坏队列的单调性,因此需要将队尾中比入队元素 x 的元素全部出队。

对于单调递减的队列,若队列为空或入队元素 x 于等于队尾元素,则入队;否则,入队会破坏队列的单调性,因此需要将队尾中比入队元素 x 的元素全部出队。

2.应用

单调队列的常用应用有:

  • 给出一组数,求这组数中第一个大/小于等于一个数 x 的数
  • 维护单调性,从而解决区间内最小/大的问题
  • 解决滑动窗口问题
  • 优化多重背包 DP、斜率优化 DP

3.实现

单调队列一般使用 STL 的 deque(双端队列) 实现即可,由于双端队列即可再队首操作又可在队尾操作,那么这样的性质就弥补了单调栈只可在尾端操作的不足,使得首段也有了一定的限制。

1)单调递增队列

deque<int> Q://双端队列
for(int i=1;i<=n;i++){
    while((!Q.empty())&&Q.back()>A[i]){//队列不为空且队尾元素大于入队元素时
       Q.pop_back();//将队列尾端大于入队元素的元素出队
       ...//更新结果
    }
    q.push_back(A[i]);//元素入队
    ...//更新结果
}

2)单调递减队列 

deque<int> Q://双端队列
for(int i=1;i<=n;i++){
    while((!Q.empty())&&Q.back()<A[i]){//队列不为空且队尾元素小于入队元素时
       Q.pop_back();//将队列尾端小于入队元素的元素出队
       ...//更新结果
    }
    q.push_back(A[i]);//元素入队
    ...//更新结果
}

【例题】

  • City Skyline(POJ-3044)(单调栈)点击这里
  • Bad Hair Day(POJ-3250)(单调栈)点击这里
  • Largest Rectangle in a Histogram(HDU-1506)(左右两次单调栈)点击这里
  • Passing the Message(HDU-3410)(左右两次单调栈)点击这里
  • Non-negative Partial Sums(HDU-4193)(单调队列)点击这里
  • Second My Problem First(HDU-3706)(单调队列)点击这里
  • Beauty Of Unimodal Sequence(HDU-6592)(LIS+单调栈)点击这里
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值