LeetCode-单调栈题目大全

42. 接雨水(困难-单调栈)×!

单调递减栈中存的是元素下标,不是下标单调递减,而是下标对应的元素单调递减。
整体思路:首先我们用的是单调递减栈,所以当 当前柱子高度比栈顶要大时,说明一定可以接水。
因为是 1 0 2 的关系
1: 如果栈不空,且当前柱子高度大于栈顶,说明出现了水沟
2: bottomIndex是水沟所在的下标, 然后出栈
3: 如果栈空了,说明没有左边的柱子,或者说当前是单调增的趋势,那么就把栈顶pop,然后break结束while,然后把当前的柱子下标入栈,维持单调递减栈的性质。
4: 由于刚才的bottomIndex已经出栈,所以现在栈顶元素是左柱子元素的下标
5: 水沟的高度就是左右柱子高度的最小值减去水沟的高度
6:这里要强调的是,由于计算了一个水沟之后,会出栈,因此,比如倒着的“土”,当中间的块出栈之后,
会变成“一”块,此时是不符合单调递减栈的,但是下一个柱子入栈时会一起计算这个“一”的面积。

class Solution {
public:
    int trap(vector<int>& height) {
        int res = 0;
        stack<int> stk; // 单调递减栈 (注意存的不是高度是下标!)
        for(int cur = 0; cur < height.size(); ++cur){
            while(!stk.empty() && height[cur] > height[stk.top()]){ // 1
                int bottomIndex = stk.top(); stk.pop(); // 2
                if(stk.empty()) break; // 3
                int l = stk.top(), r = cur; // 4
                int h = min(height[l], height[r]) - height[bottomIndex]; // 5
                res = res + (r - l - 1) * h; // 6
            }
            stk.push(cur);
        }
        return res; 
    }
};

84. 柱状图中最大的矩形(困难-单调栈)×!×

对于2 1 2  来说  添加了边界变成 0 2 1 2 0 (下面为了简化说明,指的都是元素对应的元素,而不是下标)
当栈内有 0 2 时, 1 准备入栈,发现不符合单调递增栈的性质;所以对于2 来说,以2为高度的最大矩形就已经确定,就是2;
然后1入栈,2入栈;栈内有0 1 20入栈,2为高度的矩形确定;出栈; 
此时栈内还有01 ;此时需要确定1为高度的矩形;
int curHeight = heights[st.top()]; st.pop();  // 1的下标出栈,这里能说明为什么必须获得了高度之后紧接着就要出栈,因为这样才能获得以1为高度的左端点的下标(因为现在栈内的0 1,原先它们之间是有个2的,只是以2为高度的矩形已经算完了,所以2出去了,但它比1大,所以可以用它作为左端点)
int left = st.top() + 1; // (因为是单调递增栈,如果0 1 是紧挨着,那么left就是1的下标(st.top() + 1)。如果原来它们之间还有元素,要么比1大,但是肯定已经出栈了,st.top() + 1 就是第一个大于1的元素的下标)

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        int res = 0;
        stack<int> stk;
        for(int i = 0; i < heights.size(); ++i){
            while(!stk.empty() && heights[i] < heights[stk.top()]){
                int height = heights[stk.top()]; stk.pop();
                int left = stk.top() + 1;
                res = max(res, (i - left) * height);
            }
            stk.push(i);
        }
        return res;
    }
};

85. 最大矩形(困难-单调栈)×

/*
跟84解法一样,只是要将84的解法用m - 1次求出最大值。主要还是要夯实84题。
就是以每一行为x轴算出一个柱状图的vector<int>, 然后算出最大面积就可以了。
1:这里要注意,虽然从图里看最高的一层在顶上,但是从矩阵看它就是第一行,所以i,j都从0遍历。
2:如果当前是1,那么可以加上之前的高度,只要是0,那么就是0。
3:这里要注意不能用引用,因为解法中要对heights增加左右边界,所以要传值,不能改变heights的大小。
*/
class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        int res = 0;
        vector<int> heights(n);
        for(int i = 0; i < m; ++i){ // 1
            for(int j = 0; j < n; ++j){
                if(matrix[i][j] == '1') heights[j] += matrix[i][j] - '0'; // 2
                else heights[j] = 0;
            }
            res = max(res, largestRectangleArea(heights));
        }
        return res;
    }

    int largestRectangleArea(vector<int> heights) { // 3
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        int res = 0;
        stack<int> stk;
        for(int i = 0; i < heights.size(); ++i){
            while(!stk.empty() && heights[i] < heights[stk.top()]){
                int height = heights[stk.top()]; stk.pop();
                int left = stk.top() + 1;
                res = max(res, (i - left) * height);
            }
            stk.push(i);
        }
        return res;
    }
};

739. 每日温度(中等-单调栈)√

说来搞笑,这个题一开始我是只能想到暴力解的,然后我去看题解,先看到一个栈字,我在想跟栈有什么关系?又看到单调栈,然后一瞬间就会做了。
主要是脑子里没建立起一个哈希映射,到底什么样的题能用到单调栈?
现在我还想不到答案,按我自己做过几道单调栈的题目的经验来说,一般题目是一维数组,需要用O(n2)的暴力解来做,都可以试试单调栈(不一定能用上,但是要往这想想)。

思路:
用个单调递减栈,假设temperatures为[3,2,1,4];

  • 3,2,1符合单调递减,肯定依次入栈,当i为3时,发现4大于栈顶,那么对于1来说,它的下一个最高温度就是第i = 3天,1出栈;
  • 此时栈顶为1,4仍然大于2;因为是单调递减的,2和4之间要么原来没有元素,要么有元素也肯定比2小。所以2的下一个最大温度就是3 - 1 = 2天后。
  • 最后栈内剩下的元素都是递减的,并且没有比他们高的温度的日期,又因为res的所有元素默认初始化为0,所以不用处理,直接返回。
  • 需要强调的是栈内存储的是元素的下标!不是元素!切记!
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int n = temperatures.size();
        
        stack<int> stk;
        vector<int> res(n);
        for(int i = 0; i < n; ++i){
            while(!stk.empty() && temperatures[i] > temperatures[stk.top()]){
                int d = stk.top(); stk.pop();
                res[d] = i - d;
            }
            stk.push(i);
        }   
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值