[Happy DSA] 求解直方图下的最大矩形面积

问题描述:

比较给定直方图对应的值列表为[1, 2, 4, 2, 1],那么最大的矩形面积应该是[2, 4, 2]描述的区间矩形面积为6(宽度为3,高度为2)。


关于这个问题,网上有比较多的解决方案,时间复杂度从O(n^2)、O(nlgn),到O(n) (需O(n)空间)。

http://blog.csdn.net/arbuckle/article/details/710988

最蛮力的解决方案O(n^2),就是查看所有的子直方图,求解最大的矩形面积。

O(nlgn)的解决方案符合T(n) = 2 T(n/2) + O(n)的主方法。

O(n)的解决方案比较巧妙,可以从2种不同的角度来考虑,SO上有比较不错的解答。其中比较容易理解的角度,可以参见这篇文章http://tech-queries.blogspot.com/2011/03/maximum-area-rectangle-in-histogram.html?1356186085,或者下面的解释:

  1. For each bar, we must be able to find the biggest rectangle containing this bar. So the biggest one of these n rectangles is what we want.

  2. To get the biggest rectangle for a certain bar (let's say bar[i], the (i+1)th bar), we just need to find out the biggest interval that contains this bar. What we know is that all the bars in this interval must be at least the same height with bar[i]. So if we figure out how many consecutive same-height-or-higher bars are there on the immediate left of bar[i], and how many consecutive same-height-or-higher bars are there on the immediate right of the bar[i], we will know the length of the interval, which is the width of the biggest rectangle for bar[i].

  3. To count the number of consecutive same-height-or-higher bars on the immediate left of bar[i], we only need to find the closest bar on the left that is shorter than the bar[i], because all the bars between this bar and bar[i] will be consecutive same-height-or-higher bars.

  4. We use a stack to dynamicly keep track of all the left bars that are shorter than a certain bar. In other words, if we iterate from the first bar to bar[i], when we just arrive at the bar[i] and haven't updated the stack, the stack should store all the bars that are no higher than bar[i-1], including bar[i-1] itself. We compare bar[i]'s height with every bar in the stack until we find one that is shorter than bar[i], which is the cloest shorter bar. If the bar[i] is higher than all the bars in the stack, it means all bars on the left of bar[i] are higher than bar[i].

  5. We can do the same thing on the right side of the i-th bar. Then we know for bar[i] how many bars are there in the interval.


比较难懂的角度,解释如下:

We process the elements in left-to-right order and maintain a stack of information about started but yet unfinished subhistograms. Whenever a new element arrives it is subjected to the following rules. If the stack is empty we open a new subproblem by pushing the element onto the stack. Otherwise we compare it to the element on top of the stack. If the new one is greater we again push it. If the new one is equal we skip it. In all these cases, we continue with the next new element. If the new one is less, we finish the topmost subproblem by updating the maximum area w.r.t. the element at the top of the stack. Then, we discard the element at the top, and repeat the procedure keeping the current new element. This way, all subproblems are finished until the stack becomes empty, or its top element is less than or equal to the new element, leading to the actions described above. If all elements have been processed, and the stack is not yet empty, we finish the remaining subproblems by updating the maximum area w.r.t. to the elements at the top.

For the update w.r.t. an element, we find the largest rectangle that includes that element. Observe that an update of the maximum area is carried out for all elements except for those skipped. If an element is skipped, however, it has the same largest rectangle as the element on top of the stack at that time that will be updated later. The height of the largest rectangle is, of course, the value of the element. At the time of the update, we know how far the largest rectangle extends to the right of the element, because then, for the first time, a new element with smaller height arrived. The information, how far the largest rectangle extends to the left of the element, is available if we store it on the stack, too.

We therefore revise the procedure described above. If a new element is pushed immediately, either because the stack is empty or it is greater than the top element of the stack, the largest rectangle containing it extends to the left no farther than the current element. If it is pushed after several elements have been popped off the stack, because it is less than these elements, the largest rectangle containing it extends to the left as far as that of the most recently popped element.

Every element is pushed and popped at most once and in every step of the procedure at least one element is pushed or popped. Since the amount of work for the decisions and the update is constant, the complexity of the algorithm is O(n) by amortized analysis.

def max_rectangle_area(histogram):
    """Find the area of the largest rectangle that fits entirely under
    the histogram.

    """
    stack = []
    top = lambda: stack[-1]
    max_area = 0
    pos = 0 # current position in the histogram
    for pos, height in enumerate(histogram):
        start = pos # position where rectangle starts
        while True:
            if not stack or height > top().height:
                stack.append(Info(start, height)) # push
            elif stack and height < top().height:
                max_area = max(max_area, top().height*(pos-top().start))
                start, _ = stack.pop()
                continue
            break # height == top().height goes here

    pos += 1
    for start, height in stack:
        max_area = max(max_area, height*(pos-start))

    return max_area



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值