直方图中最大的矩形(单调栈2)

题目描述

直方图是由在公共基线处对齐的一系列矩形组成的多边形。

矩形具有相等的宽度,但可以具有不同的高度。

例如,图例左侧显示了由高度为2,1,4,5,1,3,3的矩形组成的直方图,矩形的宽度都为1:
直方图中最大的矩形(单调栈2)_第1张图片
通常,直方图用于表示离散分布,例如,文本中字符的频率。

现在,请你计算在公共基线处对齐的直方图中最大矩形的面积。

图例右图显示了所描绘直方图的最大对齐矩形。

输入格式

输入包含几个测试用例。
每个测试用例占据一行,用以描述一个直方图,并以整数n开始,表示组成直方图的矩形数目。
然后跟随n个整数h1,…,hn。
这些数字以从左到右的顺序表示直方图的各个矩形的高度。
每个矩形的宽度为1。
同行数字用空格隔开。
当输入用例为n=0时,结束输入,且该用例不用考虑。

输出格式

对于每一个测试用例,输出一个整数,代表指定直方图中最大矩形的区域面积。
每个数据占一行。
请注意,此矩形必须在公共基线处对齐。

数据范围

1≤n≤100000,
0≤hi≤1000000000

输入样例:

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

输出样例:

8
4000

题解
以H[ i ]为高的矩形向左右扩展,找到能够到达的最远距离,即找到左右边界第一个小于H[ i ]的位置, 实际上就是一道单调栈的问题,用一个栈来维护一个单调递增的序列,如果栈中的某个元素比当前的数值的小,那么该元素之后的元素肯定是用不到了,所以就可以直接丢出栈, 并将该值加入栈中,遍历一遍,用ans记录最大值即可

代码如下:

//这样就形成了一个单调栈
#include
#include
using namespace std;
const int N = 1e6 + 10;
typedef long long int ll;
int l[N], r[N], h[N], q[N];
int n;
void get(int a[])
{
    int t = 0;
    h[0] = -1;
    for(int i = 1; i <= n; i++){
        while(h[q[t]] >= h[i])t--;  //找到栈中第一个比该值小的位置
        a[i] = q[t]; //记录以H[i]为高能够到达的左右边界
        q[++t] = i;  //加入栈中
    }
}
int main()
{
    while(cin >> n && n){
        for(int i = 1; i <= n; i++)
            cin >> h[i];
        get(l);  //get左边界
        reverse(h + 1, h + 1 + n);  //翻转
        get(r);  //get有边界
        ll ans = 0;
        for(int i = 1, j = n; i <= n; i++, j--)
            ans = max(ans, (ll)h[i] * (n - r[i] - l[j]));
        cout << ans << endl;
    }
    return 0;
}

你可能感兴趣的:(数据结构与算法题解总集)