单调栈,是栈内元素保持一定单调性(单调递增或单调递减)的栈。这里的单调递增或递减是指的从栈顶到栈底单调递增或递减。既然是栈,就满足后进先出的特点。与之相对应的是单调队列。
单调栈目的并不在于存储所有入栈元素。
对于一个单调递增栈,如果栈为空或入栈元素值小于栈顶元素值,则入栈;
否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。
单调递减栈反之同理。
及时排除不可能的选项,保持策略集合的高度有效性和秩序性。
时间复杂度 O(n)O(n)。
举个栗子:
例如实现一个单调递减的栈,比如现在有一组数10,7,6,18。从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。单调递减的栈反之。
比如刚刚开始时栈为空,输入10,直接入栈,栈内元素为10.
7入栈时,栈顶元素10比7大,则7入栈,栈内元素为10,7.
6入栈时,栈顶元素7比6大,则6入栈,栈内元素为10,7,6.
18入栈时,栈顶元素6比12小,6出栈,此时栈顶元素为7,仍比18小,栈顶元素7继续出栈,此时栈顶元素为10,仍比18小,10出栈,此时栈为空,18入栈,栈内元素为18。
这就是单调栈的基本思想。
应用:
1.最基础的应用就是给定一组数,针对每个数,寻找它和它右边第一个比它大的数之间有多少个数。
2.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大。
3.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列所有元素和最大。
其实实现代码有很多。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define ll long long
ll max(ll b,ll c)
{
return(b>c?b:c);
}
ll n,p;
ll a[100010]={0};
ll h[100010]={0},w[100010]={0};
ll ans;
int main()
{
while(scanf("%d",&n)&&n)
{
ans=0; p=0;
ll i;
for( i=1;i<=n;i++) scanf("%d",&a[i]);
a[n+1]=0;
for(i=1;i<=n+1;i++)
{
if(a[i]>h[p]) h[++p]=a[i],w[p]=1;
else{
ll t=0;
while(h[p]>a[i])
{
t+=w[p];
ans=max(ans,t*h[p]);
p--;
}
h[++p]=a[i],w[p]=t+1;
}
}
printf("%lld\n",ans);
}
}