单调栈
定义:
单调栈,是栈里面的特殊一种,顾名思义,单调栈里的元素都保持都单调(单调递增或单调递减):
单调递增栈:从栈底到栈顶单调递增;
单调递减栈:从栈底到栈顶单调递减;
下面就是一个单调递增栈:
算法作用:
单调栈可以求某组数中,以某个数为最小值的最大延伸区间;
下面这个题是一个很经典的单调栈的题目:
单调栈在这里的作用就是可以知道每个高度能向左向右延伸的最大宽度,从而求出最大矩形面积。
通过对这一题的解答,来更好地理解单调栈;
我对这题地基本思路就是,利用单调栈分别求出每个高度对应地左边界及右边界,然后存入数组中,最后通过计算求出最大矩阵面积;
下面就是利用单调栈求左边界:
high[0]=-1;//因为high[1]不能向左延伸,所以要存一个值来停止循环,防止数组越界;
int t=-1;
que[++t]=0;//栈底为0,因为当i=1时,high[i]要与high[0]相比较,需要注意的是:栈里面存的是high的下标,并不是下标所对应的元素
for(int i=1; i<=n; i++)//遍历high数组
{
while(high[que[t]]>=high[i])//将high[i]与左边一位相比较,因为栈顶存的便是high[i]的前一位
t--;//如果符合条件,则向左移一位
left[i]=i-que[t]-1;//left[i]存的就是对应high[i]能向左延伸的最大宽度
que[++t]=i;//更新栈顶的值
}
同理可用单调栈求右边界:
high[n+1]=-1;//寻找右边界时,是从high[n]开始遍历这个数组的,所以要同寻找左边界一样的操作,防止数组越界
int m=-1;
que[++m]=n+1;//这里同样存的是数组的下标
for(int i=n; i>0; i--)//从柱形的最后一个开始遍历,来找右边界
{
while(high[que[m]]>=high[i])//用high[i]与右边一位相比较:栈顶存的是high[i]的后一位(因为数组是从后往前遍历的)
m--;//若符合条件,则右移;
right[i]=que[m]-i-1;//right[i]存的是对应high[i]能向右延伸的最大宽度
que[++m]=i;//同样是更新栈顶的值
}
以上两段代码就是本题的核心代码,也就是本题用到单调栈的地方
上图是对用单调栈寻找左边界的部分过程分析
下面是该题的完整代码:
#include<stdio.h>
int main()
{
int n;
long long int high[101000];
while(~scanf("%d",&n))
{
if(n==0)
break;
else
{
for(int i=1; i<=n; i++)
scanf("%lld",&high[i]);
long long int left[101000],right[101000],que[101000];
int t=-1;
high[0]=-1;
que[++t]=0;
for(int i=1; i<=n; i++)
{
while(high[que[t]]>=high[i])
t--;
left[i]=i-que[t]-1;
que[++t]=i;
}
high[n+1]=-1;
int m=-1;
que[++m]=n+1;
for(int i=n; i>0; i--)
{
while(high[que[m]]>=high[i])
m--;
right[i]=que[m]-i-1;
que[++m]=i;
}
long long int sum=0,ans=0;
for(int i=1; i<=n; i++)
{
sum=high[i]*(left[i]+right[i]+1);//计算每个高度对应的矩形的面积
if(sum>ans)//通过比较找出最大面积,既最后答案。
ans=sum;
}
printf("%lld\n",ans);
}
}
}