Largest Rectangle in a Histogram HDU - 1506 解题思路 单调栈

原题目

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 1000
0

Sample Output
8
4000

===========================================================

题目大意

题目有多组数据,给出一连串的矩形高度,单个矩形默认宽度为1,高度可变且高度随机。求出这一连串按输入顺序排列的矩形在它们所能够组成的矩形块中最大的矩形面积
在这里插入图片描述

解题思路

可用通过维护一个单调递增的单调栈来求出最大矩形面积
假设输入一串矩形高度,分别为:2 4 5 6 3
在这里插入图片描述

  1. 首先把所有矩形的高度和下标存在一个结构体数组中
  2. 接着是一个for循环遍历上一步存的矩形数据(关键:①首先判断栈是否为空,主要是方便第一个数据的压栈,第一个数据和后面的数据要区分开;②如果当前的矩形高度比栈顶的矩形高度高,则压栈→维护单调递增的序列,实际上维护单调不减的栈也是可行的;③若当前矩形高度比栈顶高度要低,此时开始while循环pop栈顶元素,直到栈顶元素小于当前矩形高度,然后将当前矩形高度压栈;若当前矩形高度比栈顶高度高,则直接压栈。每pop一次都要计算一次最大矩形面积,用一个变量来记录,下面会模拟循环过程。
  3. 有一种特殊情况为一串连续不减的高度,此时不经过for循环内的while来pop栈顶的过程→栈内会存入所有的矩形高度,所以,在上一步的for循环外,还需要再增设一个循环来清空栈内元素,注意最终栈内元素个数为0。跟上一步第三点while循环类似。下面模拟循环。

===========================================================

首先构建一个结构体数组 temp[max](这里max自己赋值)

struct node
{
	int height, index;
}temp[max];

增设一个记录最大矩形面积的变量 max_square
声明一个栈的变量 stack< struct node > s

第一步,将所有数据存入temp[max]={ 2, 4, 5, 6, 3, …}

第二步,for循环遍历 temp[max] 中所有的数据(这里假设从下标0开始存入数据);
★ 要对第一个数据进行特殊判断→直接存入,并且需要初始化 max_square = temp[0].height;
★ while 循环判断 当中 n 变量为每组矩形的个数:

for(int i = 0; i < n; i++)
{
	if(s.empty())
	{
		s.push(temp[i]);
		max_square = temp[i].height;//先默认最大矩形面积为第一个面积
		continue;
	}
	while(!s.empty() && s.top() > temp[i].height)//栈不空时,判断栈顶矩形高度是否比当前矩形高度高。
	{
		//如果高于当前矩形高度,则进入while循环进行pop操作,以维护一个单调不减的序列
		//像2 4 5 6 3这个数据,一直到3才会进入while循环。只要栈内不空并且一直遇到高于3的高度的矩形,那么就要弹出栈顶元素,并且计算一次矩形面积,对比一次最大值。
		int h = s.top().height;
		s.pop();
		if(s.empty())
			max_square = max(max_square, h * (i - 1));
		else//pop后栈内存在元素的话,则执行这一个操作
			max_square = max(max_square, h * (i - 1 - s.top().index));
			//注意这里的s.top().index不是与当前矩形temp[i]相邻的那个,因为与temp[i]相邻的矩形已经在上面的指令中pop掉了
	}
	s.push(temp[i]);//每个矩形都要经历压栈的过程,只要temp[i]不比栈顶矩形高度高,就可以直接压栈。
}

2 4 5 6 一直递增,所以一直没有进入while循环,直到遇到了3,比6小,进入while循环内
此时将高度为 6 的矩形高度暂存入一个变量 h 中,可以发现此时栈内不空,所以进入else下面的指令。已知当前max_square = 2。
矩形面积等于高度成宽度,即height * 1(题目默认每个举行宽度为1),当前 3 的下标为 4,即 i = 4,栈顶矩形高度为 6,下标为 3。
现在想计算出从 2 ~ 6 能构成的最大的矩形的面积,所以要从 6 开始,从右往左扩展矩形面积,并且每轮循环更新一次 max_square。

① i = 4
栈 s [ 2, 4, 5, 6 ]
h = s.top().height = 6 > 3
s.pop()
栈 s [ 2, 4, 5 ]
s.empty() = false
max_square = 2
max_square = max(max_square, h * (i - 1 - s.top().index))
= max(2, 6 * (4 - 1 - 2)) = 6 //因为上面已经将6弹出,所以这次取到的栈顶元素的下标为2,即高度为 5 的矩形的下标。
在这里插入图片描述
② 因为栈仍然非空,并且 s.top().height > temp[i] 所以仍然在while循环内,i 不更新。
→ i = 4
栈 s [ 2, 4, 5 ]
h = s.top().height = 5 > 3
s.pop()
栈 s [ 2, 4 ]
s.empty() = false
max_square = 6
max_square = max(max_square, h * (i - 1 - s.top().index))
= max(6, 5 * (4 - 1 - 1)) = 10 //因为上面已经将5弹出,所以这次取到的栈顶元素的下标为1,即高度为 4 的矩形的下标。
此时计算的为这块矩形的面积
在这里插入图片描述
③ 因为栈仍然非空,并且 s.top().height > temp[i] 所以仍然在while循环内,i 不更新。
→ i = 4
栈 s [ 2, 4 ]
h = s.top().height = 4 > 3
s.pop()
栈 s [ 2 ]
s.empty() = false
max_square = 10
max_square = max(max_square, h * (i - 1 - s.top().index))
= max(10, 4 * (4 - 1 - 0)) = 12 //因为上面已经将4弹出,所以这次取到的栈顶元素的下标为0,即高度为 2 的矩形的下标。
此时计算的为这块矩形的面积
在这里插入图片描述
④ 可以发现,栈 s[ 2 ],s.top().height < temp[i] = 3
此时跳出while循环并且执行s.push(temp[i]),栈 s[ 2, 3 ]。
这次就进入了我们上面所说的为防止栈内仍然存在元素但跳出while循环的备用循环
代码跟上面的while循环差不多。
最后两次循环求的矩形面积为下面两张图片
)在这里插入图片描述在这里插入图片描述

while (!s.empty())
{
    int h = s.top().height;
    s.pop();
    if (s.empty())
        max_square = max(max_square, h * n);
    else
        max_square = max(max_square, h * (now_index - s.top().index));
}

有很多种方法,只讲单调栈的解题思路,剩下的处理都比较简单,不需要单独解释了,代码还是要靠自己写出来才会印象深刻。

完整代码

#include <bits/stdc++.h>
#include <algorithm>

using namespace std;

struct sair {
    int height, index;
} temp[100005];

int main() {
    int n;
    while (cin >> n) {
        if (!n)
            break;
        for (int i = 1; i <= n; i++) {
            cin >> temp[i].height;
            temp[i].index = i;
        }
        stack<sair> s;
        long long max_square = 0;
        long long h, index;
        for (int i = 1; i <= n; i++) {
            if (s.empty()) {
                s.push(temp[i]);
                max_square = temp[i].height;//先默认最大矩形面积为第一个面积
                continue;
            }
            while (!s.empty() && s.top().height > temp[i].height) {//栈不空时,判断栈顶矩形高度是否比当前矩形高度高。
                //如果高于当前矩形高度,则进入while循环进行pop操作,以维护一个单调不减的序列
                //像2 4 5 6 3这个数据,一直到3才会进入while循环。只要栈内不空并且一直遇到高于3的高度的矩形,那么就要弹出栈顶元素,并且计算一次矩形面积,对比一次最大值。
                h = s.top().height;
                index = s.top().index;
                s.pop();
                if (s.empty())
                    max_square = max(max_square, h * (i - 1));
                else//pop后栈内存在元素的话,则执行这一个操作
                    max_square = max(max_square, h * (i - 1 - s.top().index));
                //注意这里的s.top().index不是与当前矩形temp[i]相邻的那个,因为与temp[i]相邻的矩形已经在上面的指令中pop掉了
            }
            s.push(temp[i]);//每个矩形都要经历压栈的过程,只要temp[i]不比栈顶矩形高度高,就可以直接压栈。
        }
        int now_index;
        if (!s.empty())
            now_index = s.top().index;
        while (!s.empty()) {
            h = s.top().height;
            index = s.top().index;
            s.pop();
            if (s.empty())
                max_square = max(max_square, h * n);
            else
                max_square = max(max_square, h * (now_index - s.top().index));
        }
        cout << max_square << endl;
    }
    return 0;
}
  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值