错题-求相邻最大矩形面积

求相邻最大矩形面积

问题描述

青石板路的尽头堆满了财宝。小 L 感到很一阵阵失望,只能先搬走一部分财宝了。

财宝是一个个矩形紧紧挨在一起,第 i 个矩形宽度为 1 ,高度是 h i h_i hi

小 L 是一个 不会贪心 不贪心的人,所以决定只拿走最大矩形的面积这么多。

拿着拿着,小 L 突然想到,其实这个财宝墙后面还是有路的。

输入格式

第一行一个整数 n , n≤105
第二行,一行数,第 i 个数代表 * h i h_i hi​ , 0≤ h i h_i hi*​≤109

输出格式

一行,一个数,代表最大矩形面积

样例输入

7
2 1 4 5 1 3 3 

样例输出

8

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vqIu7gLG-1657092899932)(https://oj.qd.sdu.edu.cn/api/filesys/download/164786110185169007/image.png)]

算法思想:

循环每一个条形(下标是 i),找左边第一个小于当前条形高度的下标left,找右边第一个小于当前条形高度的下标right。

那么根据不让其他条形拖自己后腿、只想自己抱大腿的思想,这个条形算出的矩形面积就是

(条形值[right - 1] - 条形值[left + 1]) * 条形值[i]

但是注意!!这里的right - 1 / left + 1是广义的,你不要让他减 1 或者加 1 之后把自己都越过去了。好歹判断一下范围。

这题比较阴险,直接用单调栈计算左边第一个小于当前条形高度的下标 left,找右边第一个小于当前条形高度的下标 right 还会超时。得优化一下。

注意!!!!栈里放的是元素下标!!!!!(下面都直接用元素代替,知道具体是元素下标就好,下面的打的太赶了)

优化方法:用一个单调递减栈,每次放进一个元素的时候,如果发现当前元素比栈顶元素小,很好,这样就可以发现栈顶元素往右第一个比栈顶元素小的值。

而根据单调递减栈的定义,栈中每一个元素的下一个元素(就是朝着栈底的下一个)就是他往左第一个比他小的值的下标,就是上面的 left。那这样不就找到了以栈顶元素为木桶原理中最短板的矩形吗。

注意噢,最后一个元素放完的时候,栈里面的哪些元素都是还没有判断面积的,都要一个个取出来判断一下这些元素形成的矩形的面积。而且他们的右界的 right 就是 n - 1,因为都比当前栈顶元素大。

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

ll num[10000000] = {0};
ll revnum[10000000] = {0};
int main()
{
     ll n;
     cin >> n;
     for (ll i = 0; i < n; i++)
     {
          cin >> num[i];
     }

     ll mianji = 0;
     stack<ll> s;//单调递减栈
     for (ll i = 0; i < n;)
     {
          if (s.size() == 0 || num[s.top()] <= num[i])
          {
               s.push(i);
               i++;
          }
          else
          {
               //此时计算以num[a]为矩形的高的情况
               ll a = s.top();
               s.pop(); //此时s.top()就是离下标为a的元素的左边的第一个最小值,而i是离下标为a的元素的右边的第一个最小值
               if (s.size() == 0)
                    mianji = max(mianji, num[a] * (i - a));
               else
                    mianji = max(mianji, num[a] * (i - s.top() - 1));
          }
     }


     //最后一次一定是放进了下标n-1
     //对s中每一个数他的矩形长都可以直接到n,因为此时举行中放的下标所对应的值都是小于等于n-1所对应的值的
     while(s.size() != 0)
     {
          ll a = s.top();
          s.pop();
          if(s.size() == 0)
               mianji = max(mianji,num[a] * (n - a));
          else
               mianji = max(mianji,num[a] * (n - s.top() - 1));
     }

     cout << mianji << endl;
     return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值