单调栈的性质和使用场景

单调栈

简介

单调栈即需要保证入栈的元素是保持递增或者递减的。如果有违反递增或者递减的原则,那么就需要通过弹出栈的方式来保持单调栈的性质。
单调栈常被用来解决滑动窗口中元素最大值和最小值的问题。

实践

剑指 Offer 59 - I. 滑动窗口的最大值添加链接描述

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。

思路

观察窗口的滑动过程:
当窗口区间为 [ i , j ] \left [ i, j \right ] [i,j] ,对应的窗口中的值的集合为 { n u m i , n u m i + 1 , . . . n u m j } \left \{ num_i,num_{i+1},... num_j \right \} {numi,numi+1,...numj}, 当窗口从左向右移动一格,那么会舍弃掉 n u m i num_{i} numi,滑动窗口内增加一个值 n u m j + 1 num_{j+1} numj+1,如果集合 { n u m i , n u m i + 1 , . . . n u m j } \left \{ num_i,num_{i+1},... num_j \right \} {numi,numi+1,...numj}中只要有值比 n u m j + 1 num_{j+1} numj+1小,那么只要往右边滑动,最大值肯定不是集合中比 n u m j + 1 num_{j+1} numj+1小的值,因此可以将该集合中比 n u m j + 1 num_{j+1} numj+1小的值舍弃,照此思路,构建单调递减栈。

代码

class Solution {
    public:
    class MonotonicStack{
        deque<long long > deq;
        int max = INT_MIN;
        vector<int> vec;
    public:
        MonotonicStack(vector<int> num, int k){
            vec = num;
            for(int i = 0; i < k && i < num.size();++i)
            {
                if(num[i] > max){
                    max = num[i];
                    deq.clear();
                    deq.push_back(num[i]);
                }else{
                    while(deq[deq.size() -1] < num[i]) {
                        deq.pop_back();
                    }
                    deq.push_back(num[i]);
                }
            }
        }

    public :
        void push(int i) {
            if(vec[i] > max){
                max = vec[i];
                deq.clear();
                deq.push_back(vec[i]);
            } else {
                while(deq.size() > 0 && deq[deq.size() -1] < vec[i]) {
                    deq.pop_back();
                }
                deq.push_back(vec[i]);
            }
        }

        void pop(int start) {
            if(deq.size() > 0 && vec[start] == max) {
                max = deq.size() > 1 ? deq[1] : INT_MIN;
                deq.pop_front();
            }
        }

        int getMaxNum(){
            return this->max;
        }
    };

public :
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        if(k <= 0){
            return vector<int> {};
        }

        vector<int> vec;
        MonotonicStack* monotonicStack =  new MonotonicStack(nums, k);
        if(k >= nums.size()){
            vec.push_back(monotonicStack->getMaxNum());
        } else {
            for(int i = k; i < nums.size(); ++i) {
                vec.push_back(monotonicStack -> getMaxNum());
                monotonicStack -> pop(i-k);
                monotonicStack ->push(i);
            }
            vec.push_back(monotonicStack -> getMaxNum());
        }
        delete monotonicStack;
        monotonicStack = nullptr;
        return vec;
    }
}; 
代码理解

构造一个内部类,该类使用双向队列deque保存滑动窗口单调栈的值,在MonotonicStack的构造函数中初始化单调递减栈,然后通过循环调用MonotonicStack的pop和push函数,更新滑动窗口的 m a x max max值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值