84. 柱状图中最大的矩形

84. 柱状图中最大的矩形

思路:

方法一:

如果暴力解法,对于某一个柱子,我们让它往两边找,直到找到坑为止就算到头了,然后算面积就是了

但是这样也发现,如果我们从头往后遍历,要是下降了,那后面的肯定是前面那个的右边界,对应的他的左边界可以自己往前去搜索一下
可以用while()一直找到比它小的heights,然后就是它的左边界
但是这样的话,很容易出现重复的遍历

方法二

对于某个柱子
如果它后面是 严格下降的话,那它的右边界就是他本身,到头了
如果后面是 上升的话,那么它的右边界是不能确定的,需要往后找了,每一个都可能是它的右边界,
所以每一个都要和当前没确定右边界的柱子比较一下,如果自己比没确定边界的小,那这个位置的就找到自己属于的右边界了
但是如果比较的话,我们应该和最大的比,比完了如果比它小,那它的右边界就确定了,然后再看次小的,看看能不能确定它的右边界看样子才合理

因此我们需要一个能存储未确定右边界的数据结构,并且还能按照顺序排列,而且我们用的时候拿出来是最大值,很容易想到,就是栈
当然我们应用的过程也肯定是有序的,因为我们每次拿数的时候先看看自己是不是比没确定右边界的最大的值 严格小,
如果小的话,我就把它拿出来了,因为它的右边界已经确定了
如果大的话,我自己就塞进去了,因为我确定不了了

这样一想,好像可以再优化
我们把第一次和后面的比较的直接也算进这个循环呢,不就是把自己压入栈么?

还有一点我没有发现,他的左边界怎么确定,我一开始以为可以通过反向的方法来确定它的左边界
但是看到一个题解我突然醒悟,栈里面既然是单调增的,那么对应的这个柱子左边的不就是它的左边界么?
因为中间的被弹出去的实际上是被我和前面那个小矮子一起把它给挤出去了

class Solution {
public:
   /*
思路:
    如果暴力解法,对于某一个柱子,我们让它往两边找,直到找到坑为止就算到头了,然后算面积就是了

    但是这样也发现,如果我们从头往后遍历,要是下降了,那后面的肯定是前面那个的右边界,对应的他的左边界可以自己往前去搜索一下
    可以用while()一直找到比它小的heights,然后就是它的左边界
    但是这样的话,很容易出现重复的遍历


*/
//从左到右遍历,记录每个柱子的左边界
/*
    对于某个柱子
    如果它后面是 严格下降的话,那它的右边界就是他本身,到头了
    如果后面是 上升的话,那么它的右边界是不能确定的,需要往后找了,每一个都可能是它的右边界,
    所以每一个都要和当前没确定右边界的柱子比较一下,如果自己比没确定边界的小,那这个位置的就找到自己属于的右边界了
    但是如果比较的话,我们应该和最大的比,比完了如果比它小,那它的右边界就确定了,然后再看次小的,看看能不能确定它的右边界看样子才合理

    因此我们需要一个能存储未确定右边界的数据结构,并且还能按照顺序排列,而且我们用的时候拿出来是最大值,很容易想到,就是栈
    当然我们应用的过程也肯定是有序的,因为我们每次拿数的时候先看看自己是不是比没确定右边界的最大的值 严格小,
    如果小的话,我就把它拿出来了,因为它的右边界已经确定了
    如果大的话,我自己就塞进去了,因为我确定不了了

    这样一想,好像可以再优化
    我们把第一次和后面的比较的直接也算进这个循环呢,不就是把自己压入栈么?

    还有一点我没有发现,他的左边界怎么确定,我一开始以为可以通过反向的方法来确定它的左边界
    但是看到一个题解我突然醒悟,栈里面既然是单调增的,那么对应的这个柱子左边的不就是它的左边界么?
    因为中间的被弹出去的实际上是被我和前面那个小矮子一起把它给挤出去了
*/
    int largestRectangleArea(vector<int>& heights) {
        stack<int> st;
        st.push(-1);
        int maxArea = 0;
        int n = heights.size();
        for (int i = 0; i < heights.size(); i++) {
            while (st.top() != -1 && heights[st.top()] > heights[i]) {
                //可以夹出去当前的了,栈顶的最大面积已经确定了
                int cur = st.top();//可以确定的号
                st.pop();
                int left = st.top() + 1;
                int right = i;//左闭又开
                maxArea = max(maxArea, (right - left) * heights[cur]);
            }
            st.push(i);
        }
        while (st.top() != -1) {
            int cur = st.top();//可以确定的号
            st.pop();
            int left = st.top() + 1;
            int right = n;//一直到最后都没人消掉它,说明它可以延续到最后
            maxArea = max(maxArea, (right - left) * heights[cur]);
        }
        return maxArea;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值