其他分享
首页 > 其他分享> > 单调栈入门

单调栈入门

作者:互联网

学习单调栈的心得,以此随笔简记之。

Intro

我们由这样一个问题来引入单调栈:给定一个 N 个元素的数组,输出每一个数左边离它最近的比它小的数,没有则输出-1。

Solution

我们一下子就想出了暴力法,对于每个数都向前回溯,直到找到或者到数组头。这样的做法是 \(O(N^2)\) 的,效率比较低下。
我们来想想有什么办法可以优化:考虑这样的情况,如果 a[i] <= a[j] 且 i> j, 那么 a[j] 是不可能被作为答案的,依照这个规则,每次回溯比较时的元素应该按递增顺序排列,而且是动态变化的,那些不可能是答案的会被剔除出这个集合。我们用一个栈来保存这些可能作为答案的数。

主要步骤如下:

  1. 每次有一个新元素要入栈的时候,把栈中所有比它大的元素弹出。
  2. 输出栈顶(如果有)。
  3. 新元素入栈。

由于每个元素只会入栈和出栈一次,因此这个算法是 \(O(N)\) 的,效率大大提高了。

代码

#include <iostream>
#include <stack>

using namespace std;

const int N = 100010;

int a[N];

int main(){
    int n;
    cin>>n;
    stack<int> stk;
    for(int i = 0 ; i < n ; i ++)cin>>a[i];
    
    for(int i = 0 ; i < n ; i ++){
        while(stk.size() && a[i] <= stk.top()) stk.pop();
        if(stk.size()) cout<<stk.top()<<' ';
        else cout<<-1<<' ';
        stk.push(a[i]);
    }
    
    cout<<endl;
    
    return 0;
}

Summary

和单调队列一样,单调栈也是一种对暴力方法的优化,它剔除了冗余操作,使得效率大大提高,主要的操作就是新元素入栈时用它剔除冗余的元素。

标签:入门,int,元素,冗余,新元素,include,单调
来源: https://www.cnblogs.com/Softwarer1412/p/14604332.html