直方图最大矩形问题

来源:互联网 发布:巨灵数据库账号 编辑:程序博客网 时间:2024/06/04 18:02

在下图的七个矩形所占的位置中找出一个最大的矩形,如下所示,红框中所框出的就是这个直方图的最大矩形,面积为12。

直方图

最直观且笨拙的解法是枚举 (n+1)n/2 个区间然后利用线段树做RMQ查询区间最小值。但这样做会产生很多冗余枚举,例如区间 0~3,此区间是可扩展区间。

另一个方法是对每一个柱子,分别向左和右扩展,直到遇到低于该柱子的,则面积就是该柱子的高度乘以扩展的长度。但这种方法的复杂度同样是O(n2)

我们从左向右遍历每个矩形,并通过一个栈来存储这些矩形高度在输入数组中的索引。每个矩形(索引)仅压入栈中一次。当输入的矩形高度小于栈顶矩形的高度,那么栈顶矩形将会被弹出,然后计算矩形面积,其中矩形面积的高为弹出单个矩形条的高。现在得到了高,接下来得到左右边界后便可计算出宽度。由于当前输入的矩形i的高度小于栈顶矩形,那么以栈顶为高的矩形右边界为i。而在当前栈中若非空,那么栈中矩形条的高度一定是小于等于弹出的矩形的高度,因此左边界就确定了。(当有多个连续的高度一样的矩形条时,计算最后一个出栈的矩形时会得到最终的面积)

这里用栈记录了遍历过程中柱子的左边界,右边界就是当前遍历的高度小于栈顶高度的柱子。利用这个性质计算更新当前的最大面积矩形。对于每个弹出来的柱子来说其左边界就是这个栈中第一个低于它的柱子,也就是它的下一个元素。

对应的LeetCode题目LeetCode84

class Solution {public:    int largestRectangleArea(vector<int>& heights) {        if (heights.size() == 0) return 0;        int len = heights.size(), maxarea = 0;        stack<int> stk;        for (int i = 0; i < len; ++i) {            while (!stk.empty() && heights[i] <= heights[stk.top()]) {                int p = stk.top(); stk.pop();                int k = stk.empty() ? -1 : stk.top();                maxarea = max(maxarea, (i-k-1)*heights[p]);            }            stk.push(i);        }        while (!stk.empty()) {            int p = stk.top(); stk.pop();            int k = stk.empty() ? -1 : stk.top();            maxarea = max(maxarea, (len-k-1)*heights[p]);        }        return maxarea;    }};
原创粉丝点击