【数据结构】单调栈专题


模板题:830. 单调栈

关键要理解的地方是什么时候就弹出栈顶。本题找的是距离x最近的比x小的数,所以栈里的数如果大于等于x那么就一定不会被用到(因为x比栈顶元素更优),所以可以全部删掉(弹出),最后剩下的栈顶元素就是答案。

#include 
#include 
#include 

using namespace std;

const int N = 1e5 + 10;

int stk[N], tt;

int main()
{
    int n;
    scanf("%d", &n);
    while(n -- )
    {
        int x;
        scanf("%d", &x);
        while(tt && stk[tt] >= x) tt -- ;
        if(tt) printf("%d ", stk[tt]);
        else printf("-1 ");
        stk[++ tt] = x;
    }
    return 0;
}

131. 直方图中最大的矩形

本题要利用单调栈来优化时间复杂度。
要找到左边(右边同理)第一个比当前矩形矮的矩形,所以当栈顶元素的高度大于等于当前高度h[i],那么栈顶元素就一定不会被用到(因为当前高度更优),可以删掉(弹出),重复此操作直到栈顶元素的高度小于当前高度或栈空(无解)为止

小细节:让h[1]h[n + 1] = 1,确保所有矩形两边都有比其矮的矩形,可以方便处理边界问题。

#include 
#include 
#include 

using namespace std;

typedef long long LL;

const int N = 1e5 + 10;

int n;
int h[N], l[N], r[N], q[N];

int main()
{
    while(scanf("%d", &n), n)
    {
        for(int i = 1; i <= n; i ++ ) scanf("%d", &h[i]);
        h[0] = h[n + 1] = -1;
        int tt = 0;
        q[0] = 0;
        for(int i = 1; i <= n; i ++ )
        {
            while(h[i] <= h[q[tt]]) tt -- ;
            l[i] = q[tt];
            q[++ tt] = i;
        }

        tt = 0;
        q[0] = n + 1;
        for(int i = n; i; i -- )
        {
            while(h[i] <= h[q[tt]]) tt -- ;
            r[i] = q[tt];
            q[++ tt] = i;
        }

        LL res = 0;
        for(int i = 1; i <= n; i ++ )
            res = max(res, (LL)h[i] * (r[i] - l[i] - 1));
        printf("%lld\n", res);
    }
    return 0;
}

作者:Once.
链接:https://www.acwing.com/activity/content/code/content/3210396/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

LeetCode 456. 132模式

下图来自leetcode评论区“宫水三叶”

自己的话:
k代表的是第二大的元素,用出栈的元素更新k(有元素出栈就代表有更大的元素要入栈,所以k是第二大的元素),栈里的始终是最大的元素。所以当有nums[i] < k就认为找到了一组解。

class Solution {
public:
    bool find132pattern(vector& nums) {
        int k = INT_MIN;
        stack stk;
        for(int i = nums.size() - 1; i >= 0; i -- )
        {
            if(nums[i] < k) return true;
            while(stk.size() && stk.top() < nums[i])
            {
                k = max(k, stk.top());
                stk.pop();
            }
            stk.push(nums[i]);
        }
        return false;
    }
};