问题描述
在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi。这n个矩形构成了一个直方图。例如,下图中六个矩形的高度就分别是3, 1, 6, 5, 2, 3。
请找出能放在给定直方图里面积最大的矩形,它的边要与坐标轴平行。对于上面给出的例子,最大矩形如下图所示的阴影部分,面积是10。
请找出能放在给定直方图里面积最大的矩形,它的边要与坐标轴平行。对于上面给出的例子,最大矩形如下图所示的阴影部分,面积是10。
输入格式
第一行包含一个整数n,即矩形的数量(1 ≤ n ≤ 1000)。
第二行包含n 个整数h1, h2, … , hn,相邻的数之间由空格分隔。(1 ≤ hi ≤ 10000)。hi是第i个矩形的高度。
第二行包含n 个整数h1, h2, … , hn,相邻的数之间由空格分隔。(1 ≤ hi ≤ 10000)。hi是第i个矩形的高度。
输出格式
输出一行,包含一个整数,即给定直方图内的最大矩形的面积。
样例输入
6
3 1 6 5 2 3
3 1 6 5 2 3
样例输出
10
思路:第一次看见这题的想法就是:
1、先输入数据,存入一个数组里
2、遍历数组中的每个元素,并找出当前数组元素左边和右边第一个小于当前数组元素的数
3、由刚才得到的数组元素的下标,计算这段距离中有多少个矩形,
4、当前元素 * 距离 = temp
5、比较最终答案和temp,如果temp大于最终答案ans,那么ans = temp,否则继续
但是提交之后发现会超时,每次反复的运算大大增加了时间复杂度,所以笔者从别人那里借鉴到一种方法:
这种方法的大体思路是这样的,输入数据之后,遍历每个数据,对于其中的每一个数据a[i], 从下表i到n-1之间,找到最小的数a[j],用它乘以i到j之间矩形的个数,如果得到的答案大于最终要输出的答案,那么就把这个答案赋值给最终答案。
说的比较笼统,一会再深入讲解,先看看代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #include<string> 5 #include<cstring> 6 using namespace std; 7 const int N = 1003; 8 int a[N]; 9 10 int main(){ 11 int n; 12 while(cin>>n){ 13 for(int i =0 ;i < n;++i){ //输入数据 14 cin>>a[i]; 15 } 16 int ans = -1; //先设置最终答案ans为-1 17 for(int i = 0 ; i< n;++i){ //对于每个元素a[i] 18 int low = a[i]; //当前最小值low设置为a[i] 19 for(int j = i ; j < n;++j){ //对于i后面的每个元素 20 if(low > a[j]) //如果a[j] 比 当前设置的最小值还要小,那么最小值设置为a[j] 21 low = a[j]; 22 int temp = (j - i + 1) * low; //设置标记变量temp 为这段区间中的总和 23 if(temp > ans) 24 ans = temp; 25 } 26 } 27 cout<<ans<<endl; 28 } 29 return 0; 30 }
我想还有许多人对二层循环那里不明白,其实笔者刚开始也不太明白,下面就来讲解一下这里吧、、、
有一个问题,就是总是向右边遍历,那么左边的数据怎么算?
其实,在不断向右边遍历的过程中,我们如果把下标 i 看成后面每个数的左边界就好了、、、
假如 i 现在为0,那么右边的每个数的左边界都是 0,并且按照代码中写的,不断找到i 到j之间的最小值,那么 0 到 i 之间的最小值的最终结果是不是就是n * 最小值呢
如果还不明白,还可以这么想,假如就三个数据,a1,a2,a3, 假如a1 比a2 小的前提下,
(1)a3 大于 a2 并且大于 a1 那么对于a3来说,最大值就是a3
(2)a3小于a2 并且大于a1 ,那么对于a3来说,最大值就是a3 * 2
、、、、、
所以从前向后遍历的过程,其实就是不断对于下标为i后面的某个元素j的左方向遍历过程、、、
大家懂了吗,如果还有问题,希望大家能提出来,笔者深知能力有限,但是能帮助大家的还是会尽力的、、