leetcode_84.柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

在这里插入图片描述
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。

在这里插入图片描述
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

示例:

输入: [2,1,5,6,2,3]
输出: 10

解析:
方法一:暴力法
最简单也是最慢的方法,对每一种可能的范围进行计算,寻找这个范围内最小的矩形,然后计算面积。
时间复杂度O(n3),用O(n)的时间寻找最小矩形,共O(n2)个可能的范围
空间复杂度O(1)

方法二:优化暴力法
对于每一个矩形柱子,能够彻底包裹它的最大矩形取决于三个值:柱子的高度h,左侧第一个小于它高度的柱子的位置l,右侧第一个小于它高度的柱子的位置r。而这个矩形的面积是(r-l-1)*h
因此对数组中的每一个元素,分别向左右寻找第一个小于它的元素,之后便可以计算出包括它的最大矩形,选择最大的便是答案
时间复杂度O(n2),用O(n)的时间计算总共n个柱子
空间复杂度O(1)

方法三:分治法
我们每次选择所有元素中最小的那个。
对于这个元素来说,最大矩形可能存在与三个地方:1、这个元素左侧。2、这个元素右侧。3、包括这个元素
对于1和2来说,我们递归调用函数即可,对于3,既然这个元素是最小的,因此包括这个元素的最大矩形面积便是这个元素值乘数组长度。之后选择三种可能中最大的便是结果。
平均时间复杂度O(nlogn),最坏时间复杂度O(n2)
最坏空间复杂度O(n),最坏情况下n次调用函数递归栈空间

方法四:栈
这是本人使用的方法
基本原理源自方法二,使用栈来巧妙的避免了多次重复扫描。
遍历数组,如果栈为空或者栈顶元素小于当前元素,则入栈。
直至当前元素小于栈顶元素,此时的情况恰好为方法二中的描述。对于当前栈顶元素,根据入栈的要求,必然在栈中为最大,而左侧第一个小于它的元素恰好为栈中第二个元素,而右侧第一个小于它的元素即为当前元素。
于是可以套用方法二的计算方法,计算出包括当前栈顶元素的最大矩形面积。
当遍历结束,若栈中存在元素,按照上文的方法继续计算。
使用栈的方法,保证每个元素仅入栈出栈各一次。
时间复杂度O(n)
空间复杂度O(n)

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        
        stack<int> st;
        int res = 0;
        int p = 0;
        while(p!=heights.size()){
            if(st.empty()) st.push(p++); 
            else{ //若栈空或栈顶元素小于当前元素,入栈
                if(heights[p]>=heights[st.top()]) st.push(p++);
                else{ //否则根据当前情况计算结果
                    int h = heights[st.top()];
                    st.pop();
                    res = max(res,(p-(st.empty()?-1:st.top())-1)*h);
                }
            }
        } //遍历完成后对栈中剩下元素进行计算
        while(!st.empty()){
            int h = heights[st.top()];
            st.pop();
            res = max(res, (int)((heights.size()-(st.empty()?-1:st.top())-1)*h) );
        }
        return res;
    }
};



发布了112 篇原创文章 · 获赞 0 · 访问量 367

猜你喜欢

转载自blog.csdn.net/qq_37292201/article/details/103889707