最大矩形
一:题目描述
在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi。这n个矩形构成了一个直方图。例如,下图中六个矩形的高度就分别是3, 1, 6, 5, 2, 3。
请找出能放在给定直方图里面积最大的矩形,它的边要与坐标轴平行。对于上面给出的例子,最大矩形如下图所示的阴影部分,面积是10。
二:理解
①.法一:暴力法
开始这道题用了一下暴力,便利了所有的元素,比如[2, 1, 5, 6, 2, 3],遍历所有右区间[2], [2, 1], [2, 1, 5], …, [2, 1, 5, 6, 2, 3], [1], [1, 5], [1, 5, 6], …, [1, 5, 6, 2, 3], [5], [5, 6], …, [5, 6, 2, 3], …, [3],得到各自的矩阵面积,返回最大值。
时间复杂度为O(n^2),提交了一下,没过(时间问题)。
代码跑了一下,是没有问题的:
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
int n; //矩阵的个数
int num[1005]; //矩阵的高度
//暴力
int main()
{
int count = 0;
cin >> n;
for(int i = 0; i < n; i++)
cin >> num[i];
for(int i = 0; i < n; i++)
{
int minnum = 10005;
for(int j = i; j < n; j++)
{
if(minnum > num[j])
minnum = num[j]; //找最小的矩阵高
count = max(count, (minnum * (j - i + 1))); //矩阵个数乘以矩阵最小高度
}
}
cout << count;
return 0;
}
代码解释:这个纯暴力就是上面介绍的那样实现;应该比较好理解!
结果:
②.单调栈算法(时间复杂度为 O(n),借助单调性处理问题的思想在于即使排除不可能的选项,保持策略集合的高度有效性和秩序性,从而为我们做出决策提供更多的条件和可能方法。)
思路:
建立一个栈,保存若干个矩形,并且栈顶元素到栈底元素始终由大到小(一直保持的形式)。我们从左到右依次扫描每一个矩形: 如果当前矩形比栈顶矩形高,直接进栈;否则不断取出栈顶,直至栈为空或者栈顶矩形的高度比当前最后一个矩形小。
在出栈过程中,我们累计被弹出的矩形的宽度之和,并且每弹出一个矩形,就用它的高度乘上累积的宽度更新答案。整个出栈过程结束后,我们把高度作为当前矩形的高度、宽度为累计值的新矩形入栈。
整个扫描结束后,我们把栈中剩余的矩形依次弹出,按照与上面相同的办法更新答案。
代码:
#include<bits/stdc++.h>
using namespace std;
//变量
int n;
int num[1010],numstack[1010],weight[1010];
//单调栈
int main()
{
int temp = 0;
long long count = 0;
cin >> n;
for(int i = 0; i < n; i++)
cin >> num[i];
for(int i = 0; i <= n; i++)
{
if(num[i] > numstack[temp])
{
numstack[++temp] = num[i];
weight[temp] = 1;
}
else
{
int maxwidth = 0;
while(num[i] < numstack[temp])
{
maxwidth+=weight[temp];
count = max(count,(long long)maxwidth*numstack[temp--]);
}
numstack[++temp] = num[i];
weight[temp] = maxwidth + 1;
}
}
cout << count << endl;
return 0;
}