单调栈之前在力扣做过几道题,最近在acwing做了几道复习一下。
1.单调栈裸题
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
用一个最小栈存每个数左边第一个比它小的数
#include<cstdio>
using namespace std;
const int maxn=1e5+5;
int n,m,q;
int a[maxn];
int s[maxn],tt=-1;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
for(int i=0;i<n;i++)
{
while(tt!=-1&&s[tt]>=a[i]) tt--;
if(tt==-1) printf("-1 ");
else printf("%d ",s[tt]);
s[++tt]=a[i];
}
return 0;
}
2.直方图中最大的矩形
直方图是由在公共基线处对齐的一系列矩形组成的多边形。
矩形具有相等的宽度,但可以具有不同的高度。
例如,图例左侧显示了由高度为 2,1,4,5,1,3,3 的矩形组成的直方图,矩形的宽度都为 1:
通常,直方图用于表示离散分布,例如,文本中字符的频率。
现在,请你计算在公共基线处对齐的直方图中最大矩形的面积。
图例右图显示了所描绘直方图的最大对齐矩形。
这道题比裸题稍微麻烦一点,我们首先给出暴力的思路,即找到每个矩形左边和右边最靠近它的并且高度比它小的矩阵,记朝左边能伸出的长度为
l
l
l,右边为
r
r
r,则面积为
(
r
+
l
−
1
)
∗
h
(r+l-1)*h
(r+l−1)∗h,暴力求出r和l时间复杂度为
o
(
n
2
)
o(n^2)
o(n2),用单调栈可以优化成
o
(
n
)
o(n)
o(n)。
#include<cstdio>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn=1e5+5;
int n;
int h[maxn];
int q[maxn],tt=-1;
int l[maxn],r[maxn];
ll res;
int main()
{
while(scanf("%d",&n)&&n)
{
res=0;
for(int i=1;i<=n;i++) scanf("%d",&h[i]);
h[0]=h[n+1]=-1;//处理边界问题
q[++tt]=0;//这样写两边就不用特判了
for(int i=1;i<=n;i++)
{
while(h[q[tt]]>=h[i]) tt--;
l[i]=i-q[tt];
q[++tt]=i;
}
tt=-1;
q[++tt]=n+1;
for(int i=n;i;i--)
{
while(h[q[tt]]>=h[i]) tt--;
r[i]=q[tt]-i;
q[++tt]=i;
}
for(int i=1;i<=n;i++) res=max(res,(ll)(r[i]+l[i]-1)*h[i]);
printf("%ld\n",res);
}
return 0;
}
3.最大矩阵
大概题意:求一个01矩阵中含有1的最大矩阵的面积
将每一行看成一个直方图,如下图所示
这样对每一行按照第二题求一次最大面积即可,时间复杂度为
o
(
n
m
)
o(nm)
o(nm)
#include<cstdio>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn=1e3+5;
int n,m;
int s[maxn][maxn],l[maxn],r[maxn];
int q[maxn],tt=-1;
int work(int h[])
{
h[0]=h[m+1]=-1;
tt=-1;
q[++tt]=0;
for(int i=1;i<=m;i++)
{
while(h[q[tt]]>=h[i]) tt--;
l[i]=i-q[tt];
q[++tt]=i;
}
tt=-1;
q[++tt]=m+1;
for(int i=m;i;i--)
{
while(h[q[tt]]>=h[i]) tt--;
r[i]=q[tt]-i;
q[++tt]=i;
}
int res=0;
for(int i=1;i<=m;i++)
{
res=max(res,h[i]*(r[i]+l[i]-1));
}
return res;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char c;
scanf("%s",&c);
if(c=='F') s[i][j]=s[i-1][j]+1;
}
}
int res=0;
for(int i=1;i<=n;i++) {
int t=work(s[i]);
res=max(res,t);
}
printf("%d",res*3);
return 0;
}
这道题输入有坑,要用
scanf("%s",&c)
或者
scanf(" %c",&c)
来读入字符