[单调栈] aw152. 城市游戏(单调栈+最大矩形面积进阶)

1. 题目来源

链接:84. 柱状图中最大的矩形
链接:131. 直方图中最大的矩形

相关题解:[单调栈] lc84. 柱状图中最大的矩形、aw131. 直方图中最大的矩形(单调栈+算法对比+模板题)

进阶题[单调栈] aw3516. 最大面积(单调栈+最大矩形面积进阶+今日头条2021+好题)

2. 题目解析

单调栈经典应用,和 [单调栈] lc84. 柱状图中最大的矩形、aw131. 直方图中最大的矩形(单调栈+算法对比+模板题) 一样思路。不过需要转换一下。

枚举每行,每行的柱形高度是以该行为底到上面连续 F 的个数。单调栈求面积即可。

求柱形的话采用递推即可,若 a[i][j]=='F'h[i][j]=h[i-1][j]+1,否则 h[i][j]=0


时间复杂度 O ( n 2 ) O(n^2) O(n2)
空间复杂度 O ( n 2 ) O(n^2) O(n2)


单调栈标准写法:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1005;

int n, m;
char a[N][N];
int h[N][N], l[N], r[N];
int stk[N], tt;

int main() {
    scanf("%d%d", &n, &m);
    
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            cin >> a[i][j];             // 空格隔开,采用 cin 来读,不要使用 scanf,会读入空格
    
    for (int i = 1; i <= n; i ++ ) 
        for (int j = 1; j <= m; j ++ ) {
            if (a[i][j] == 'F') 
                h[i][j] = h[i - 1][j] + 1;
        }
    
    int res = 0;
    for (int i = 1; i <= n; i ++ ) {
        tt = 0;
        for (int j = 1; j <= m; j ++ ) {
            while (tt && h[i][stk[tt]] >= h[i][j]) tt -- ;
            if (tt) l[j] = stk[tt];
            else l[j] = 0;		// 左边界是 0
            stk[++tt] = j;
        }
        tt = 0;
        for (int j = m; j; j -- ) {
            while (tt && h[i][stk[tt]] >= h[i][j]) tt -- ;
            if (tt) r[j] = stk[tt];
            else r[j] = m + 1;
            stk[++tt] = j;
        }
        
        for (int j = 1; j <= m; j ++ ) res = max(res, h[i][j] * (r[j] - l[j] - 1));
    }
    printf("%d\n", 3 * res);
    return 0;
}

简洁的写法,设置哨兵,避免空栈判断:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1005;

int n, m;
int h[N][N], l[N], r[N];
int stk[N];

int work(int h[]) {
    int tt = 0;
    h[0] = h[m + 1] = -1;
    stk[0] = 0;					// 设置哨兵,栈永远不空
    for (int i = 1; i <= m; i ++ ) {
        while (h[stk[tt]] >= h[i]) tt -- ;
        l[i] = stk[tt];
        stk[++tt] = i;
    }
    
    tt = 0;
    stk[0] = m + 1;				// 设置哨兵,栈永远不空
    for (int i = m; i; i -- ) {
        while (h[stk[tt]] >= h[i]) tt -- ;
        r[i] = stk[tt];
        stk[++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() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ ) {
            char c;
            cin >> c;
            if (c == 'F')
                h[i][j] = h[i - 1][j] + 1;
        }

    int res = 0;
    for (int i = 1; i <= m; i ++ ) res = max(res, work(h[i]));
    cout << res * 3 << endl;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值