单调栈(算法篇)

算法之单调栈

注意:单调栈是一种数据结构,并非是一种算法,但是我们做一些算法题的时候,这种单调性结构有妙用,所以我姑且放在算法篇进行讲解

单调栈

概念

  • 单调栈是一种数据结构,但是因为经常使用就将其放入算法
  • 单调栈就是栈内的元素呈单调递增或者单调递减的(一般指栈顶到栈底)
  • 将一个元素插入单调栈时,为了维护栈的单调性,需要在保证将该元素插入到栈顶后整个栈满足单调性的前提下弹出最少的元素
  • 例如:例如,单调递增栈中自顶向下的元素为{0,11,45,81},插入元素14时为了保持单调性需要依次弹出0、11,操作后栈变为{14,45,81}
  • 时间复杂度为O(n)

适用场景

  • 单调栈可以求解出某个元素左边或者右边第一个比它大或者小的元素

  • 可以将其分为具体四种问题:

    1. 寻找左侧第一个比当前元素大的元素
    2. 寻找左侧第一个比当前元素小的元素
    3. 寻找右侧第一个比当前元素大的元素
    4. 寻找右侧第一个比当前元素小的元素

各问题解决做法

总结

  • 查找比当前大的元素用单调递增栈,查找比当前小的元素用单调递减栈
  • 左侧查找就看插入栈时的栈顶元素,从右侧查找就看弹出栈时即将插入的元素
  1. 寻找左侧第一个比当前元素大的元素

    • 构造一个单调递增栈(从栈顶到栈底)
    • 从左到右遍历元素
    • 如果当前元素大于栈顶元素,则将其加入(也就是将栈里面小于当前元素的都弹出再插入);
    • 如果小于,则当前栈顶元素就是当前遍历的元素左侧第一个比它大的元素
    • 如果插入时的栈为空,则说明左侧不存在比当前元素大的元素
  2. 寻找左侧第一个比当前元素小的元素

    • 构造一个单调递减栈(从栈顶到栈底)
    • 从左到右遍历元素
    • 如果当前元素小于栈顶元素,就加入栈中
    • 如果大于,则当前栈顶元素就是当前遍历元素左侧第一个比它小的元素
    • 如果插入时的栈为空,则说明左侧不存在比当前元素小的元素
  3. 寻找右侧第一比当前元素大的元素

    • 构造一个单调递增栈(从栈顶到栈底)
    • 从左到右遍历元素
    • 如果当前遍历元素大于当前栈底元素,则当前栈顶元素的右侧第一个比它大的元素就是当前遍历元素
    • 如果小于,则将其加入栈中
    • 如果在栈中的元素没有被弹出,说明栈中剩下的元素没有右侧比它大的元素
  4. 寻找右侧第一个比当前元素小的元素

    • 构造一个单调递减栈(从栈顶到栈底)
    • 从左到右遍历元素
    • 如果当前遍历元素小于当前栈顶元素,则当前栈顶元素的右侧第一个比它小的元素就是当前遍历元素
    • 如果大于,则加入栈中
    • 如果在栈中的元素没有被弹出,说明栈中剩下的元素没有右侧比它小的元素

模板代码

  1. 单调递增栈

    int main(){
        stack<int>st;
        for(int i=0;i<nums.size();++i){
            while(!st.empty()&&nums[i]>nums[st.top()]){
                st.pop();
            }
            st.push(i);
        }
    }
    
  2. 单调递减栈

    int main(){
        stack<int>st;
        for(int i=0;i<nums.size();++i){
            while(!st.empty()&&nums[i]<nums[st.top()]){
                st.pop();
            }
            st.push(i);
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Moon2144

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值