单调栈及其应用

题目描述
给定一个可能含有重复值的数组 arr,找到每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置。返回所有位置相应的信息。位置信息包括:两个数字 L 和 R,如果不存在,则值为 -1,下标从 0 开始。
示例1
输入 [3,4,1,5,6,2,7]
返回值 [[-1,2],[0,2],[-1,-1],[2,5],[3,5],[2,-1],[5,-1]]

单调栈的应用很局限,只有这种应用,要不是找左边/右边离自己最近的最小的值,要不就是左边/右边找离自己最大的值,右边亦然。左边的话遍历顺序从前到后,右边的话遍历顺序从后向前。
为什么应用单调栈呢?给定一个数列[a,b,c,d,e] 找该序列中比自己小的最近的数的位置,比如对于d而言,如果b>c 那么离d最近的元素是c,b不会被选到。可以手动模拟一下样例的执行过程便可以深刻感受到单调栈的用法。
求解左边的数字从0开始循环,求解右边的数字从最后一位开始循环。其中栈保存的是下标,栈用的是数组模拟的不是用的库函数。(用数组模拟的原因:栈的操作入栈出栈,入栈相当于数组指针向后移动,出栈相当于数组指针向前移动,因此模型时需要使用到数组存储到什么位置啦)

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums intvector 
     * @return intvector<vector<>>
     */
    vector<vector<int> > foundMonotoneStack(vector<int>& nums) {
        // write code here
        int n=nums.size();
        vector<vector<int>> res(n,vector<int>(2,0));
        
        int stkL[n],stkH[n];
        int tl=0,th=0;
        for(int i=0;i<n;i++)
        {
            while(tl&&nums[stkL[tl]]>=nums[i]) tl--;
            if(tl) res[i][0]=stkL[tl];
            else res[i][0]=-1;
            stkL[++tl]=i;//存储的是下标
        }
        for(int i=n-1;i>=0;i--)
        {
            while(th&&nums[stkH[th]]>=nums[i]) th--;
            if(th) res[i][1]=stkH[th];
            else res[i][1]=-1;
            stkH[++th]=i;
        }
        return res;
    }
};

leetcode 739 每日温度
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90]
输出: [1,1,0]

寻找右边比它大的元素。使用单调栈,且遍历顺序从后向前遍历。

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int n=temperatures.size();
        stack<int> stk;
        vector<int> ans(n);
        for(int i=n-1;i>=0;i--)
        {
            while(stk.size() && temperatures[i]>=temperatures[stk.top()]) stk.pop();
            if(stk.size()) ans[i]=stk.top()-i;
            stk.push(i);
        }
        return ans;
    }
};

84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
在这里插入图片描述
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
示例 2:
在这里插入图片描述
输入: heights = [2,4]
输出: 4
提示:
1 <= heights.length <=105
0 <= heights[i] <= 104

盛水最多的容器不同的一点是,矩形不是中空的,是实心的,如果按照盛水最多的容器那种做法,会使得矩阵出现中空这种现象。

既然是实心的,那么就需要知道当前数字 x 可以延伸的左右边界是多少,进一步就需要知道左右两边分别对于当前 x 最左边/最右边离 x 最小的数字是多少? 那么就需要使用单调栈来做该题目。特殊情况,如果左右两边没有比自己小的数字,那么左边赋值为-1,右边赋值为n,最后求解最大的矩阵时只需要遍历每个数字可以看做高,将每个数字乘以矩阵的宽 (right[i]-left[i]-1) 即可得到。

class Solution {
public:
    int largestRectangleArea(vector<int>& height) {
        stack<int> stk;
        int n=height.size();
        vector<int> left(n),right(n);
        for(int i=0;i<n;i++)
        {
            int x=height[i];
            while(stk.size() && height[stk.top()]>=x) stk.pop();
            if(stk.empty()) left[i]=-1;
            else left[i]=stk.top();
            stk.push(i);
        }
        stk=stack<int>();
        for(int i=n-1;i>=0;i--)
        {
            int x=height[i];
            while(stk.size()&&height[stk.top()]>=x) stk.pop();
            if(stk.empty()) right[i]=n;
            else right[i]=stk.top();
            stk.push(i); 
        }
        int ans=0;
        for(int i=0;i<n;i++)
        {
            ans=max(ans,height[i]*(right[i]-left[i]-1));
        }
        return ans;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值