week5 A - 最大矩形(单调栈)

一、题目描述

给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是2, 1, 4, 5, 1, 3, 3, 他们的宽都是1,其中最大的矩形是阴影部分。
在这里插入图片描述

Input

输入包含多组数据。每组数据用一个整数n来表示直方图中小矩形的个数,你可以假定1 <= n <= 100000. 然后接下来n个整数h1, …, hn, 满足 0 <= hi <= 1000000000. 这些数字表示直方图中从左到右每个小矩形的高度,每个小矩形的宽度为1。 测试数据以0结尾。

Output

对于每组测试数据输出一行一个整数表示答案。

Sample Input

7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0

Sample Output

8
4000

二、思路概述
1.把矩形的高存进数组p里面,然后从前往后,依次进单调递增栈;每次判断一个高的时候,如果必须弹出一个高,那么以这个高为高的矩形的最右边边界就是此时判断的高的编号;
2.判断最左边边界的方法,也是使用单调递增栈,但是是从后往前把数组元素压入栈,来找到左边界。
3.找到两个边界后就可计算可实现的矩形的面积,找出最大面积,即为所求答案。

三、细节
1.第一次出现了失误,是因为h的数据范围虽然在2e9的范围内,但是在计算面积sum的时候,面积有可能会超过2e9,所以面积要求是longlong型的。与此同时,计算sum的公式右边如果h和length都是int型,就会爆掉,无法强转成longlong。所以要求h和length至少一个是longlong型的。

	long long area=0;
	long long sum=0;
    for(int i=0;i<n;i++)
    {
    	sum=p[i].h*length[i];
    	if(area<sum)area=sum;
	}
	 cout<<area<<endl;
	

2.感觉如果数据范围比较大的话,即使没有超出范围,还是尽量用longlong吧。
3.这一题比较麻烦的地方就是分析如何利用单调栈,来找出矩形使用一个高时,宽最大应该如何计算。

四、完整代码

#include<iostream>
#include<stack>
using namespace std;

struct point
{
	long long h;
	int num; 
};

void area(point *p,int n)
{
	stack<point> xp1;//单增栈,计算每个高度往右伸展 
	stack<point> xp2;
	
	int *left=new int[n];
	int *right=new int[n];
	int *length=new int[n];
	//计算右边界 
	for(int i=0;i<n;i++)
	{
		while(!xp1.empty() &&xp1.top().h>p[i].h)
		{
			point pp=xp1.top() ;
			xp1.pop() ;
			right[pp.num ]=i;
		}		
		xp1.push(p[i]); 	
	}
	while(!xp1.empty() )
	{
		point pp=xp1.top() ;
		xp1.pop() ;
		right[pp.num ]=n;
	}
	
	//计算左边界 
	for(int i=n-1;i>=0;i--)
	{
		while(!xp2.empty() &&xp2.top().h>p[i].h)
		{
			point pp=xp2.top() ;
			xp2.pop() ;
			left[pp.num ]=i;
		}		
		xp2.push(p[i]); 	
	}
	while(!xp2.empty() )
	{
		point pp=xp2.top() ;
		xp2.pop() ;
		left[pp.num ]=-1;
	}

	for(int i=0;i<n;i++)
	{ 
	    length[i]=right[i]-left[i]-1;
	}
	long long area=0;
	long long sum=0;
    for(int i=0;i<n;i++)
    {
    	sum=p[i].h*length[i];//谨慎,右边计算的时候可能会爆掉 
    	if(area<sum)area=sum;
	}
	 cout<<area<<endl;
	
}
int main()
{
	int n;//n来表示直方图中小矩形的个数
	while(cin>>n)
	{
		if(n==0)
		break;
		point *p=new point[n];//h表示直方图中从左到右每个小矩形的高度
		for(int i=0;i<n;i++)
		{
		 scanf("%lld",&p[i].h);//存储数据 
		 p[i].num =i;
		}		 
		area(p,n);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值