LeetCode 84. Largest Rectangle in Histogram(单调栈)

题目来源:https://leetcode.com/problems/largest-rectangle-in-histogram/

问题描述

84. Largest Rectangle in Histogram

Hard

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.

Example:

Input: [2,1,5,6,2,3]
Output: 10

------------------------------------------------------------

题意

给定一组数列组成直方图,求直方图中的最大矩形面积。

------------------------------------------------------------

思路

单调栈。

首先考虑当直方图的高度是从左往右递增的,我们应该如何解决这个问题呢?当直方图的高度递增时,例如[1,2,2,3,5,6],我们可以很容易求出每个高度数值(1,2,3,5,6)对应的矩形面积(1*6, 2*5, 3*3, 5*2, 6*1)。

那当直方图的高度不是单调递增时候怎么求解呢?答案是用单调栈维护一个从栈底到栈顶递增的直方图。具体做法是,单调栈中存储一个类,类的两个属性分别是高度height和这个高度上连续的直方体个数cnt。在遍历直方图的过程中,为了维护栈的单调性,如果当前直方体的高度h大于等于单调栈的栈顶高度,则该直方体入栈;如果h小于单调栈的栈顶高度,则单调栈循环弹出直方体,每弹出一个高度数值的连续直方体集合,就更新一下最大面积,直到栈空或h大于等于新的栈顶,此时要将等于弹出个数的高为h的连续直方体集合入栈。

由于实际算法执行的时候可以记录连续多个等高的直方体的个数而不用逐个弹出栈顶的每一个直方体,因此算法的时间复杂度可能是O(n).

下面用[2,1,5,6,2,3]的例子来演示这个算法。

Step

单调栈

当前弹出面积

最大面积

0

[] <= 2

null

0

1

[2] <= 1

2

0

2

[1,1] <= 5

null

2

3

[1,1,5] <= 6

null

2

4

[1,1,5,6] <= 2

6

2

5

[1,1,5,5] <= 2

10

6

6

[1,1,2,2,2] <= 3

null

10

7

[1,1,2,2,2,3]

null

10

8

[1,1,2,2,2,2]

3

10

9

[1,1,1,1,1,1]

8

10

10

[]

4

10

注:实际代码中单调栈存储的是(高度,连续等高的直方体个数)对象,例如单调栈[1,1,5,6]被存储为[(1,2), (5,1), (6,1)]. 同时在多对元素出栈时单调栈的情况也与表中演示的(第4~6行)有所不同上表仅作示例性说明,不是代码的真正执行过程。

------------------------------------------------------------

代码

class Solution {
    class Pair {
        int height, cnt;
        
        public Pair(int height, int cnt)
        {
            this.height = height;
            this.cnt = cnt;
        }
    }
    
    public int largestRectangleArea(int[] heights) {
        Stack<Pair> stack = new Stack<Pair>();
        int maxSize = 0, curSize = 0, curCnt = 0;
        for (int h: heights)
        {
            if (stack.empty())
            {
                stack.push(new Pair(h, 1));
            }
            else if (h == stack.peek().height)
            {
                stack.peek().cnt++;
            }
            else if (h > stack.peek().height)
            {
                stack.push(new Pair(h, 1));
            }
            else
            {
                Pair poped = stack.pop();
                curCnt = poped.cnt;
                curSize = poped.height*curCnt;
                maxSize = curSize>maxSize?curSize:maxSize;
                while (!stack.empty() && h < stack.peek().height)
                {
                    poped = stack.pop();
                    curCnt += poped.cnt;
                    curSize = poped.height*curCnt;
                    maxSize = curSize>maxSize?curSize:maxSize;
                }
                if (stack.empty())
                {
                    stack.push(new Pair(h, curCnt+1));
                }
                else if (stack.peek().height == h)
                {
                    stack.peek().cnt += curCnt+1;
                }
                else
                {
                    stack.push(new Pair(h, curCnt+1));
                }
            }
        }
        curCnt = 0;
        while (!stack.empty())
        {
            Pair poped = stack.pop();
            curCnt += poped.cnt;
            curSize = curCnt*poped.height;
            maxSize = curSize>maxSize?curSize:maxSize;
        }
        return maxSize;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值