代码题(39)— 柱状图中最大的矩形、最大矩形

1、84.柱状图中最大的矩形

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

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

以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]

图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

示例:

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

  方法一:

  考虑回文串的一种从中间往两头找的算法,首先遍历,对于每一个柱状图来说,向左右搜索,直到找到比他小的柱状图(假设为l和r),这样算出该柱状图的对应的矩形的面积为(r-l+1)*heights[cur]。复杂度:O(n*n)。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        if(heights.empty())
            return 0;
        int n = heights.size();
        int res = 0;
        for(int i=0;i<n;++i)
        {
            int j = i-1, k=i+1;
            while(j>=0 && heights[j]>=heights[i])
                j--;
            while(k<n && heights[k]>=heights[i])
                k++;
            res = max(res, heights[i]*(k-j-1));
        }
        return res;
    }
};

  方法二:

  简单来说,维护一个单调栈,如果当前元素大于栈顶元素,则把当前元素的坐标入栈,否则,弹出栈顶元素直到当前元素可入栈。

  在栈顶元素弹出时,把弹出的元素当成最短木板,计算能组成的最大面积是多少。时间复杂度:O(n)。

  为什么栈中保存的是下标而不是数组本身的值? 因为,维护的是递增序列,计算面积总是以短板为高度,中间部分也是取短板的高度,宽度计算在内。

  可以按照下面的理解,以栈中保存值本身而不是下标为例:

  比如2,1,5,6,2,3

  (1)2进栈。s={2}, result = 0

  (2)1比2小,不满足升序条件,因此将2弹出,并记录当前结果为2*1=2。将2替换为1重新进栈。s={1,1}, result = 2

  (3)5比1大,满足升序条件,进栈。s={1,1,5},result = 2

  (4)6比5大,满足升序条件,进栈。s={1,1,5,6},result = 2

  (5)2比6小,不满足升序条件,因此将6弹出,并记录当前结果为6*1=6。s={1,1,5},result = 6,2比5小,不满足升序条件,因此将5弹出,并记录当前结果为5*2=10(因为已经弹出的5,6是升序的)。s={1,1},result = 102比1大,将弹出的5,6替换为2重新进栈。s={1,1,2,2,2},result = 10

  (6)3比2大,满足升序条件,进栈。s={1,1,2,2,2,3},result = 10,栈构建完成,满足升序条件,因此按照升序处理办法得到上述的max(height[i]*(size-i))=max{3*1, 2*2, 2*3, 2*4, 1*5, 1*6}=8<10

  综上所述,result=10

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

2、85. 最大矩形

给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例:

输入:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
输出: 6

  此题是上面那道的的扩展,这道题的二维矩阵每一层向上都可以看做一个直方图,输入矩阵有多少行,就可以形成多少个直方图,对每个直方图都调用 “直方图中最大的矩阵”中的方法,就可以得到最大的矩形面积。那么这道题唯一要做的就是将每一层构成直方图,由于题目限定了输入矩阵的字符只有 '0' 和 '1' 两种,所以处理起来也相对简单。

  方法是,对于每一个点,如果是‘0’,则赋0,如果是 ‘1’,就赋 之前的height值加上1。(相当于用“1”来组成直方图)

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> height(n);
        int res = 0;
        for(int i=0;i<m;++i)
        {
            for(int j=0;j<n;++j)
            {
                height[j] = (matrix[i][j] == '0'? 0 : (height[j]+1));//如果先加的一行此处位置为0,则就是0,否则在原来的基础上加1
            }
            res = max(res,helper(height) );
        }
        return res;
        
    }
    
    int helper(vector<int>& heights) {
        int res = 0;
        if(heights.empty())
            return res;
        stack<int> st;
        heights.push_back(0);
        for(int i=0;i<heights.size();++i)
        {
             while (!st.empty() && heights[st.top()] >= heights[i]) {
                int cur = st.top(); 
                st.pop();
                int dis = st.empty() ? i : (i - st.top() - 1);
                res = max(res, heights[cur] * dis);
            }
            st.push(i);
        }
        return res;
    }
};
原文地址:https://www.cnblogs.com/eilearn/p/9432240.html