题目:
直方图是由在公共基线处对齐的一系列矩形组成的多边形。
矩形具有相等的宽度,但可以具有不同的高度。
例如,图例左侧显示了由高度为2,1,4,5,1,3,3的矩形组成的直方图,矩形的宽度都为1:
2559_1.jpg
通常,直方图用于表示离散分布,例如,文本中字符的频率。
现在,请你计算在公共基线处对齐的直方图中最大矩形的面积。
图例右图显示了所描绘直方图的最大对齐矩形。
输入格式
输入包含几个测试用例。
每个测试用例占据一行,用以描述一个直方图,并以整数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
解析:
运用栈,可以先考虑往左看,计算每一个能够往左延续多少,再考虑往右能延续多少,最后把每一个的可能情况相加并减去多算的一个本身去乘以本身面积,得到每个数据跟最大值比较,即可得到答案
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
long long s[110000],tem[110000],left[110000],right[110000];
int main()
{
long long n,x,count,res,max;
while(scanf("%lld",&n)!=EOF)
{
if(n==0) break;
s[0]=-1; //设置左边界,防止出栈时越界
s[n+1]=-1; //设置有边界,防止出栈时越界
for(x=1;x<=n;x++)
scanf("%lld",&s[x]);
count=0;
tem[0]=0; //第一个赋值为0,0代表的就是s数组的第一个边界值-1
for(x=1;x<=n;x++) //往左看
{
while(s[tem[count]]>=s[x]) //如果左边的比右边大,说明这个数可以往左延续,那个这个数据就出栈,而延续个数用x-tem[count]便可得知,这样算还可保留已经 出栈的个数,方便后续计算
{
count--;
}
left[x]=x-tem[count]; //记录当前数往左可延续多少,
tem[++count]=x; //把坐标入栈,也就是第几个还在站内,方便计算不相邻的可延续情况算入之前已经出栈但在当前情况下可延续的数据
}
count=0;
tem[0]=n+1; //第一个赋值为n+1,记录有边界,防止出站时越界
for(x=n;x>=1;x--) //往右看,方法同上面差不多
{
while(s[tem[count]]>=s[x])
{
count--;
}
right[x]=tem[count]-x; //因为是往右看,所以tem数组的数据比当前下标大,所以同上不同
tem[++count]=x;
}
max=-1;
for(x=1;x<=n;x++)
{
res=s[x]*(left[x]+right[x]-1); //left[x]+right[x]-1是计算这个数据往左往右以及减去的一个重复的自己共可以延续多少,再乘以本身面积
if(res>max) max=res; //比较最大
}
printf("%lld\n",max);
}
return 0;
}
代码中tem数组主要记录坐标,以方便计算往左往右可延续多少,以往左举例,x-tem[count]可算出此数可往左延续几个,而代码中的while循环则出栈可以延续的数据,因为tem数组记录的是下标,所以用当前下标x减去whil循环停止时tem[count]记录的下标值便可知道延续多少个,而每次出栈后手影响的还有tem数组,他会少了一些数据,使得数据之间有间距,而这个间距就是已经出栈的个数,方便之后算延续时不漏掉已经出栈的数据