一.题目
题目描述:在一堆的柱状图中找到一个最大的矩形,并输出矩形的面积
如图所示:
![](https://img-blog.csdnimg.cn/img_convert/f45cbd93e10f8541a60d89efdf00864a.png)
二.题目分析
答案矩形的高度
我们先去寻找一下这些矩形的规律:
答案矩形的下底面肯定是贴着地的,因为这些柱子的底面在同一平面,答案矩形肯定不是飘着的
答案矩形的上底面肯定是某一个柱子的顶部,比如上图的矩形,它的上底面就是第三个矩形的上底面,一但没有贴着某一个柱子的上底面,那一定还可以向上拓展。
以上两个规律应该显而易见可以得到,大家可以自己想几个样例试一试。
那么我们只需要去算出,以每一个柱子的高度为答案矩形高度的矩形面积,并使用ans数组不断更新就可以了
那么矩形的高度已经解决了,接下来就是矩形的宽度了。
答案矩形的宽度
如图:
![](https://img-blog.csdnimg.cn/img_convert/08de9627c2ab3e864e6faf7f723d9418.png)
我们对第四个高度为2的柱子进行考察:
最左边:可以画到第二个柱子
最右边:可以画到第六个柱子
宽度为:6-2+1=5
我们也可以理解为:向左向右分别寻找第一个比考察柱子短的柱子,把这两个的标号相减再-1就是宽度
最左边:第一个柱子是第一个小于考察柱子的柱子,为1号柱
最右边:第七个柱子是第一个小于考察柱子的柱子,为7号柱
宽度为:7-1-1=5
那么单调栈的作用,就是便于我们去寻找两边的第一个小于目标柱子的柱子。
三.什么是单调栈
顾名思义,单调栈就是栈里的所有的元素都是单调递增或单调递减,那么在这个题目中,我们需要使用单调递增的栈
四.代码和解释
struct n {
int height, index;
}temp;
stack<n> s;
首先建立一个结构体,存储的是每一个元素的高度(height)和下标(index),并建立一个存储结构体n的栈。
if (s.empty() || s.top().height < a) {
temp.height = a;
temp.index = i;
s.push(temp);
}
如果栈为空,或者新的元素是大于栈顶元素的,那么新来的元素不会破坏栈的单调性,那么就把这个柱子入栈。
特别注意:这里的s.empty()和s.top().height < a不能调换顺序,包括后面的判断也要先判断栈是否为空。c++中的&&和||是短路与和短路或,但一个栈是空的时候,我们再去调用这个栈的栈顶,会报错,所以我们先去判断栈时候为空,如果是空的话,表达式s.empty() || s.top().height < a 已经为true了,那么这个表达式就被||短路了,也就是s.top().height < a就不会被执行了,也就是top一定不会去作用到一个空栈上。包括下面的!s.empty() && s.top().height >= a的表达式不能调换位置
else if (!s.empty() && s.top().height >= a) {
while (!s.empty() && s.top().height >= a) {
temp_height = s.top().height;
s.pop();
if (s.empty()) {
length = i - 1;
} else {
length = i - s.top().index - 1;
}
ans = max(ans, (long long)length * temp_height);
}
temp.height = a;
temp.index = i;
s.push(temp);
}
这里的话我们去判断,如果栈不为空的时候并且新来的元素小于栈顶元素,那么新来的元素就破坏了栈的单调递增
那么我们就需要把这个栈的栈顶出栈,直到这个数进栈后不会破坏这个栈的单调递增。
我们用temp_height来存储这个栈顶的元素的高度,此时搞定了矩阵的高度。
至于矩阵的宽度,我们想一下,此时加进去的a比栈顶元素矮,那么a这个元素一定是栈顶元素右侧第一个小于a的元素,此时我们把栈顶元素出栈,此时的栈顶元素就是左侧第一个小于的元素
![](https://img-blog.csdnimg.cn/img_convert/e64f3d228fe59983aee457dd025306b0.png)
也就是说,对于一个单调递增的单调栈,考察第i个元素,那么可知,第i-1个元素是i左侧第一个小于i的元素,这个规律大家可以自己想几个测试数据,多画一画,应该不难得出。
当然如果当前柱子已经是当前栈的唯一元素,我们就加一个特判。
最后更新ans,并将新的数据进栈。
if (!s.empty() && i == num) {
while (!s.empty()) {
temp_height = s.top().height;
temp_w = s.top().index;
if (s.size() == 1) {
length = temp_w;
s.pop();
} else {
s.pop();
length = temp_w - s.top().index;
}
ans = max(ans, (long long)length * temp_height);
}
}
最后,我们要处理一下,i=num时,将栈中的剩余元素处理一下。
逻辑和刚才一样,同时对栈中只有唯一元素时特判一下。
然后由于题目要求有多组测试,所以把数组和变量清空一下
num = a = length = temp_height = temp_w = 0;
ans = 0;
while (!s.empty()) s.pop();
此时,游戏结束,如有不懂,可以私信我
AC代码:
#include<iostream>
#include<stack>
using namespace std;
struct n {
int height, index;
}temp;
stack<n> s;
int num, a, length, temp_height, temp_w;
long long ans;
int main(){
while (cin >> num && num) {
for (int i = 1; i <= num; i++) {
scanf_s("%d", &a);
if (s.empty() || s.top().height < a) {
temp.height = a;
temp.index = i;
s.push(temp);
}
else if (!s.empty() && s.top().height >= a) {
while (!s.empty() && s.top().height >= a) {
temp_height = s.top().height;
s.pop();
if (s.empty()) {
length = i - 1;
}
else {
length = i - s.top().index - 1;
}
ans = max(ans, (long long)length * temp_height);
}
temp.height = a;
temp.index = i;
s.push(temp);
}
if (!s.empty() && i == num) {
while (!s.empty()) {
temp_height = s.top().height;
temp_w = s.top().index;
if (s.size() == 1) {
length = temp_w;
s.pop();
}
else {
s.pop();
length = temp_w - s.top().index;
}
ans = max(ans, (long long)length * temp_height);
}
}
}
printf("%lld\n", ans);
num = a = length = temp_height = temp_w = 0;
ans = 0;
while (!s.empty()) s.pop();
}
return 0;
}