acwing 131.直方图中最大的矩阵

acwing 131.直方图中最大的矩阵
算法:(数组模拟栈+单调栈)
思路:
1.首先先思考最大矩形的特点,一定是以某个矩形i的高为最大矩形的高,然后以这个矩形i往两边扩展而来的最大矩形;所以想到暴力做法就是遍历i,每个矩形i往两边扩展出一个以矩形i的高为高的最大矩形,所以,然后更新答案,遍历完成之后就得到最终答案。
2.暴力的思路看看n的范围10^5如果双重循环就TLE了,所以想着怎么去优化它;比如对矩形i往左边扩展是,如果扩展到左边的一个比较矮矩形,那么,更左边更高的矩形就被限制住了,不会拿来构成最大矩形,所以就不会存在递减序列。联想到单调栈,假设我们维护了一个单调递增栈,矩形i就能寻找到距离它最近的比它矮的矩形下标j,那么j到i之间的都是和矩形i等高或者更高的矩形,自然就能构成最大矩形;右边同理
3.向左和向右都要维护一个单调栈,然后记录距离它最近的比它矮的矩形下标,就要l和r的两个数组来存
4.每个矩形高大于等于0,矩形标号从1~n,所以在边界的时候很容易越界过去,比如矩形i往左寻第一个比它矮的矩形时,可能寻找下标1,但是此时万一下标1的矩形高等于0,那么栈弹出的时候会因为0号位好似有个矩形高为0,把它弹出,就会继续向左好像寻找到数组里0标号的高度默认为0的矩形,但其实没有这个矩形,那么就会寻找错误;因为这种情况的存在,所以我们直接在左边界更左边0号位放置一个-1高的矩形,在右边界更右边n+1号位放置-1高的矩形,这样就不会寻找左右边界的时候超出去了

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6+5;

typedef long long ll;

int h[N],l[N],r[N];	//l记录往左寻的最靠近矩形i的比它矮的矩形标号,r记录往右寻的靠近矩形i的比它矮的矩形标号
int stk[N];	//拿来维护单调栈的模拟数组,记录下标 
int main ()
{
	int n;
	while (cin>>n,n)
	{
		for (int i=1;i<=n;i++) cin>>h[i];
		
		h[0]=h[n+1]=-1;	//防止寻找下标越界 
		
		
		stk[0]=0;	//因为设置了一个-1高的0号矩形,所以提前入栈0标号 
		int tt=0;	//栈0号位已经有东西了,所以tt从0开始 

		for (int i=1;i<=n;i++)
		{
			while (h[stk[tt]]>=h[i]) tt--;	//已经入栈了初始标号,所以不用判断栈非空;遇到非递增,就弹出栈顶 
			l[i]=i-stk[tt]-1;		//l数组记录矩形i到栈顶记录的标号之间有多少个比矩形i更高或者等高的矩形 
			stk[++tt]=i;
		}
		
		
		stk[0]=n+1;	//因为设置了一个-1高的n+1号矩形,所以提前入栈n+1标号
		tt=0;		//同上 
		
		for (int i=n;i>=1;i--)	//注意这里是从n号位开始到1号位了 
		{
			while (h[stk[tt]]>=h[i]) tt--;
			r[i]=stk[tt]-i-1;		//同上 
			stk[++tt]=i;
		}
		
		ll ans=0;	//宽是10^5数量级,高是10^9数量级,10^5*10^9会爆int,所以用long long,下面的潜质类型转换也是为了防止爆int 
		for (int i=1;i<=n;i++) ans=max(ans,(ll)(l[i]+r[i]+1)*h[i]);	//答案更新;然后宽的时候要加上1,因为还有矩形i本身也算一个 
		cout<<ans<<endl;
	}
	return 0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值