HUD 1506 Largest Rectangle in a Histogram(单调栈的应用)(题目详解)

Largest Rectangle in a Histogram

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 20566    Accepted Submission(s): 6267


Problem Description
A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectangles with the heights 2, 1, 4, 5, 1, 3, 3, measured in units where 1 is the width of the rectangles:

Usually, histograms are used to represent discrete distributions, e.g., the frequencies of characters in texts. Note that the order of the rectangles, i.e., their heights, is important. Calculate the area of the largest rectangle in a histogram that is aligned at the common base line, too. The figure on the right shows the largest aligned rectangle for the depicted histogram.
 

Input
The input contains several test cases. Each test case describes a histogram and starts with an integer n, denoting the number of rectangles it is composed of. You may assume that 1 <= n <= 100000. Then follow n integers h1, ..., hn, where 0 <= hi <= 1000000000. These numbers denote the heights of the rectangles of the histogram in left-to-right order. The width of each rectangle is 1. A zero follows the input for the last test case.
 

Output
For each test case output on a single line the area of the largest rectangle in the specified histogram. Remember that this rectangle must be aligned at the common base line.
 

Sample Input
 
 
7 2 1 4 5 1 3 3
4 1000 1000 1000 10000
 

Sample Output
 
 
8
4000
 

Source

题意:给出n个矩形的高,求最大能拓展的矩形的面积,可利用单调栈解决

初学单调栈,参考的 点击打开链接单调栈介绍:

单调栈和单调队列一样,都是维护一个单调序列。

单调栈性质:

(1)后进先出

(2)只在栈顶进行入栈、出栈操作

(3)单调性指的是从栈顶元素到栈底元素符合严格的单调递增或者单调递减。

具体进栈过程的本质是:维护单调性。以单调递减栈为例,若当前进栈元素为u,从栈顶开始遍历,大于等于u的元素出栈,直到栈顶元素小于u或者栈为空,然后u入栈。

例子:

进栈元素分别为:2,1,4,5,1,3,3

2进栈:[2]

2出栈,1进栈:[1]

4进栈:[1,4]

5进栈:[1,4,5]

5出栈,4出栈,1出栈,1进栈:[1]

3进栈:[1,3]

3出栈,3进栈:[1,3]


模板:  单调栈下面是一个单调递增的栈

 //找在左边离自己最近的比自己小的元素

for(int i=1;i<=n;i++)

{

while(!s.empty()&&h[s.top()]>=h[i])//如果栈不空且栈顶元素比自身大

s.pop();//那就出栈,直到找到第一个比自己小的

if(s.empty()) l[i]=0;

//如果栈空了还没找到,那在它之前就没有比它小的元素,赋成0

//即它的高度可以拓展到前面所有的矩形,因为它最低,前面的比它高的高出来的也没用,都得“将就”着它,类似最短板的原理

else l[i]=s.top();//即从i点向左遍历的第一个高度比i小的点是第几个

s.push(i);

}

//找在右边离自己最近的比自己小的元素

for(int i=n;i>=1;i--)

{

       while(!s.empty()&&h[s.top()]>=h[i])

       s.pop();

       if(s.empty()) r[i]=n+1;//如果栈空了还没找到,那在它之后就没有比它小的元素,赋成n+1

       else r[i]=s.top();

       s.push(i);

}

例如:

h :   2  1  4  5  1  3  3  //n个元素

l:     0  0  2  3  0  5  5  //左边离自己最近的小于自己的是第几个元素
r:    2  8  5  5  8  8  8  //右边离自己最近的小于自己的是第几个元素

总结:一个元素向左(右)遍历的第一个比它小的数的位置就是将它插入单调栈时栈顶元素的值,若栈为空,则说明不存在这么一个数。然后将此元素的下标存入栈,就能类似迭代般地求解后面的元素

AC代码:
#include <stdio.h>
#include <stack>
#include <algorithm>
using namespace std;
//数组过大要放全局变量 	
long long int h[100005];//h[i]表示第i个矩形的高 
long long int l[100005];//l[i]表示从第i个矩形向左遍历,第一个比它高度低的是第l[i]个矩形 (在第i个矩形左边 且 离它最近的 高度比它低的矩形 是第l[i]个矩形 ) 
long long int r[100005];//r[i]表示从第i个矩形向右遍历,第一个比它高度低的是第r[i]个矩形 
//有了左右边界,那么界限内的矩形高度都比它自身高,那么它自身的高度就是一个最短板,可以采用它的高度拓展矩形 
int main()
{
	int n;
	stack<int> s;
	while(~scanf("%d",&n))
	{
		if(n==0) return 0;
		for(int i=1;i<=n;i++)//下标从1开始 
			scanf("%lld",&h[i]);
			
        while(s.size()) s.pop();//清空栈 
        
        for(int i=1;i<=n;i++)//找在左边离自己最近的比自己小的元素 
        {
        	while(!s.empty()&&h[s.top()]>=h[i]) //如果栈不空且栈顶元素比自身大
			s.pop();//那就出栈,直到找到第一个比自己小的
			
			if(s.empty()) l[i]=0;//如果栈空了还没找到,那在它之前就没有比它小的元素,赋成0
			//即它的高度可以拓展到前面所有的矩形,因为它最低,前面的比它高的高出来的也没用,都得“将就”着它 ,类似最短板的原理
			else l[i]=s.top();//即从i点向左遍历的第一个高度比i小的点是第几个 
			s.push(i);
		}
		
		while(s.size()) s.pop();//清空栈
		
		for(int i=n;i>=1;i--)//找在右边离自己最近的比自己小的元素 
		{
			while(!s.empty()&&h[s.top()]>=h[i])
			s.pop();
			if(s.empty()) r[i]=n+1;//如果栈空了还没找到,那在它之后就没有比它小的元素,赋成n+1
			else r[i]=s.top();
			s.push(i);
		} 
		
		long long int ans=-1; 
	        //遍历每一个高(自身的高就是最短板,在自身左右边界内没有比它还短的),能求出最大拓展的矩形的面积
		for(int i=1;i<=n;i++)
		ans=max(ans,h[i]*(r[i]-l[i]-1));
	    printf("%lld\n",ans);
	}
	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值