LeetCode84:柱状图中最大的矩形

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

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

  

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

首先定义:

  对柱形图中的一个矩形i来说,我们计算以heights[i]为高的矩形的最大面积时,以i为起点,向左找到第一个小于heights[i]的矩形j,向右找到第一个小于heights[i]的矩形k。(j,k)区间,也即[j+1,k-1]所围成的以heights[i]的矩形就是i的最大矩形。当然,这个矩形面积不一定是整个柱形图中的最大矩形,但一定是i的最大矩形,因为i是[j+1,k-1]区间内最短的一个,如果这个区间内有某个矩形z的高heights[z]小于heights[i],则区间所围成的矩形最大面积应该以heights[z]为高,因为z才是真正的短板。

  因此,如果我们要计算整个柱形图中的最大面积,其实只要找到所有的以i(i=0....n-1)的高为高的最大矩形,在里面选一个就好了。

  实际操作上可以对每个矩形都向左找一个上界,向右找一个下界,但这样时间复杂度实际上是处于O(n^2)。

  因此可以考虑用一个单调递增的栈,栈中存储的是矩形的索引。

首先为什么要选取一个单调递增栈呢?因为如果采取单调递增栈,则对栈中任意一个元素i来说,i以前入栈的元素一定都比它矮,也就是说我们不用去寻找上界,它的上界一定就是第i-1个元素。

然后为什么要存储矩形的索引呢?因为根据索引我们既可以马上得到它的高heights[i],也可以马上得到它的宽,只要用索引加减就可以了。

计算流程:

1).最开始入栈-1(-1的作用是当栈中只有一个矩形时,它的上界就是-1,不然栈中只有这一个矩形的话上界不方便计算)。

2).如果当前矩形i的高>=heights[aux.top()],则入栈。这是为了保持栈的单调递增性质。

3).如果当前矩形i的高<heights[aux.top()],则将aux.top()出栈,对出栈的这个元素j来说,他在栈中的前一个元素a一定是小于它的,所以一定是它的上界。现在的这个元素i的高也一定是小于它的,所以是它的下界,因此以aux.top()为高的最大矩形的上下界就已经确定下来为(a,i),也就是[a+1,i-1]了,对这个矩形j来说,它的最大面积为heights[j]*(i-1-(a+1)+1)。计算得到这个面积area后,将他与max作对比并做记录。继续与现在的aux.top()和i做对比,出栈直到heights[aux.top()]<heights[i]时,在将i入栈。

4)循环这个过程。当然,如果说矩形的最后几个元素高都是递增的,最后会发现栈中除-1外还有元素,因此在最开始我们就在heights中加入一个0,这个0的作用就是用于最后对付栈未空的情况,因为0一定可以作为矩形们的下界。

代码:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
		if(heights.size()==0)
			return 0;
		stack<int> aux;
		int max=INT_MIN;
		aux.push(-1);
		heights.push_back(0);
		for(int i=0;i<heights.size();i++)
		{
			if(aux.top()==-1||heights[aux.top()]<=heights[i])
				aux.push(i);
			else
			{
				while(aux.top()!=-1&&heights[aux.top()]>heights[i])
				{
					int h=heights[aux.top()];
					aux.pop();
					int area=h*(i-aux.top()-1);
					if(area>=max)
						max=area;
				}
				aux.push(i);
			}
		}
		if(max<=0)
			return 0;
		return max;
    }
};

  

猜你喜欢

转载自www.cnblogs.com/lxy-xf/p/11287822.html