• [leetcode]84.Largest Rectangle in Histogram ,O(n)解法剖析


    Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

    Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

    The largest rectangle is shown in the shaded area, which has area = 10 unit.

    For example,
    Given heights = [2,1,5,6,2,3],
    return 10.

    题目描述:就是给你一组数组,每个位置上的数都代表一个宽度为1的矩形柱,求你能得到的面积最大的矩形柱的面积。这里要注意,如果是[2,1,2],输出的结果应该是3而不是2,是从3个矩形柱中截取高度为1的矩形拼接而成的。

    没有什么题目是纯暴力不能解决的,当然考虑到时间复杂度和空间复杂度,这个还是有可能会崩的。

    以下是一个O(n)的解法,并不是我的原创。

    首先我们看一下下面的例子:

    height的内容是 [5,6,7,8,3],特点是除了最后一个,前面全部保持递增,且最后一个立柱的高度小于前面所有立柱高度。

    对于这种特点的柱状图,如果使用上面所说的“挨个使用每一个柱状图的高度作为矩形的高度,求面积”的方法,还需要用嵌套循环吗?

    我们知道除了最后一个,从第一个到倒数第二个立柱的高度都在升高,那么如果挨个使用每一个柱的高度作为矩形的高度,那么依次能得到的矩形的宽度就可以直接算出来:使用5作为高度可以使用前四个立柱组成 4*5的矩形,高度6可以组成3*6的矩形... 因此只需要遍历一次,选出最大面积即可。

    对于这种类型的柱状图,最大矩形面积的时间复杂度是O(n)。

    我们将这种特点的柱状图称为“波峰图”。

    下面介绍新的解法的步骤:

    (1) 在height尾部添加一个0,也就是一个高度为0的立柱。作用是在最后也能凑成上面提的那种“波峰图”。

    (2) 定义了一个stack,然后遍历时如果height[i] 大于stack.top(),进栈。反之,出栈直到栈顶元素小于height[i]。

    由于出栈的这些元素高度都是递增的,我们可以求出这些立柱中所围成的最大矩形。更妙的是,由于这些被弹出的立柱处于“波峰”之上(比如弹出i 到 i+k,那么所有这些立柱的高度都高于 i-1和 i+k+1的高度),因此,如果我们使用之前所提的“左右延伸找立柱”的思路解,以这些立柱的高度作为整个矩形的高度时,左右延伸出的矩形所包含的立柱不会超出这段“波峰”,因为波峰外的立柱高度都比他们低。“波峰图”其实就是求解最大矩形的“孤岛”,它不会干扰到外部。

    (3) 由于比height[i]大的元素都出完了,height[i]又比栈顶元素大了,因此再次进栈。如此往复,直到遍历到最后那个高度为0的柱,触发最后的弹出以及最后一次面积的计算,此后stack为空。

    (4) 返回面积最大值。

    栈中存的不是高度,而是height的索引,这样做的好处是不会影响宽度的计算,索引值相减 = 宽度。

     1  int largestRectangleArea(vector<int> &h) {  
     2        stack<int> S;  
     3       h.push_back(0);  
     4       int sum = 0;  
     5        for (int i = 0; i < h.size(); i++) {  
     6             if (S.empty() || h[i] > h[S.top()]) S.push(i);  
     7            else {  
     8                 int tmp = S.top();  
     9                 S.pop();  
    10                  sum = max(sum, h[tmp]*(S.empty()? i : i-S.top()-1));  
    11                  i--;  
    12            }  
    13        }  
    14        return sum;  
    15   }  

    此解法最大亮点就在于:

    (1) stack里存的是index,计算面积时的宽度使用 index的差值,所以虽然stack 弹出了立柱,但是不影响宽度的计算,依然可以计算面积。

    (2) 这种解法本质上是查看以每一个立柱为矩形高度,求出最大面积,但是它通过入栈出栈,把整个height变成一组组“波峰图”来解,这种高度布局下,最大面积的计算是O(n)的,然后将所有波峰图的最大面积取最大值。最后做到了以O(n)的时间复杂度覆盖了所有的立柱。

    非常值得学习。

  • 相关阅读:
    致5年后的自己
    基础知识回顾——属性
    基础知识回顾——类和对象
    基础知识回顾——面向对象编程
    基础知识回顾——函数
    基础知识回顾——流程控制
    基础知识回顾——列表和字典
    基础知识回顾——元组和字符串
    基础知识回顾——通用序列操作
    XPath Checker和Firebug安装与使用
  • 原文地址:https://www.cnblogs.com/SarahLiu/p/5946464.html
Copyright © 2020-2023  润新知