leetcode 84. Largest Rectangle in Histogram 柱状图中最大的矩形

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

这个题没有写数据范围,有点坑,先开始想了个简单的二维dp,最后发现有一组数据有五万多个数,直接爆炸

dp思路很简单假设dp[i][j]是代表第i个柱子如果选择高度j,所能达到的最大面积

比较容易得到方程dp[i][j]=dp[i-1][j]+j 这里把所有dp[i][j]都提前初始化为0

有个可以做的优化是j不一定要把每一个高度都遍历一次,可以提前用一个map存好出现过的高度。只遍历这些高度即可。

这么做复杂度O(n^2),遇到上万的数据,直接扑街

扑街之后还一直在想dp,后来实在想不出来,看了下他下面的相关话题。

很尴尬,压根就没有动态规划这一栏。。

然后看着有栈,试着换了个思路

 

 首先分析,逐列扫描,会发现如果当前高度为h[i],并且小于h[i-1],这个时候,说明前面那一列要么保留,要么只能使用h[i]的高度。这里可以细想一下,如果保留那h[i-1]的高度最多能往前延伸多少呢,很明显是更上一个小于h[i-1]的位置,根据位置的差以及h[i-1]的高度,可以直接计算出面积。如果不保留h[i-1],那么就是考虑h[i]往前能够延伸多远

 

这里可以设计一个栈,然后逐列扫描

如果h[i]大于栈顶元素就压入栈,并记录他的下表,如果h[i]小于栈顶元素,那么这时开始挨个把栈中的元素弹出来。注意因为是栈所以最后进去的最早出来,所以一定是距离h[i]更近的下表会先出来。这个时候计算以当前弹出的元素高度往前最多能走多远,因为这个栈只有大于栈顶才会进栈,所以栈顶元素一定大于等于下一个元素,所以可以拿下一个栈顶和当前弹出元素之间的下表差乘以当前元素高度得到面积。弹出所有比h[i]大的元素后,把h[i]进栈

 

最后比较每一个弹出栈的元素所能得到的最大面积,就可以拿到最大值了

 

然后注意一点,那个栈可能最后扫描完所有列之后还有剩余元素,这个时候需要把这个栈的元素都吐出来在算一次。这里为了避免写特判,所以我当了回懒狗,手动在最初的传入数据末尾加了个高度为-1的元素。这样保证最后栈一定为空

 

代码:(耗时8ms)

struct histogram{
	int h;
	int id;
	histogram(){}
	histogram(int th,int tid)
	{
		this->h=th;
		this->id=tid;
	}
};

class Solution{
public:
    int largestRectangleArea(vector<int>& heights)
	{
		heights.push_back(-1);
		int n=heights.size(),result=0;
		if(n==1)
			return 0;
		stack<histogram> s;
		s.push(histogram(heights[0],0));
		for(int i=1;i<n;++i)
		{
			if(heights[i]>=s.top().h)
				s.push(histogram(heights[i],i));
			else
			{
				while(true)
				{
					if(s.empty() || heights[i]>s.top().h)
					{
						s.push(histogram(heights[i],i));
						break;
					}
					int h1=s.top().h,id1=s.top().id;
					int area1=h1*(i-id1);
					s.pop();
					if(s.empty())
					{
						int area2=h1*id1;
						result=max(result,area1+area2);
					}
					else
					{
						int id2=s.top().id;
						int area2=h1*(id1-id2-1);
						result=max(result,area1+area2);
					}
				}
			}
		}
		return result;
	}
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值