1. 题目来源
链接:84. 柱状图中最大的矩形
链接:131. 直方图中最大的矩形
相关题解:
2. 题目解析
字节 2021 年 5 月 9 日笔试题。
做这道题前,得先掌握 单调栈,再把 131. 直方图中最大的矩形 搞了,再把 [单调栈] aw152. 城市游戏(单调栈+最大矩形面积进阶)
搞了,再来做这道题。
其实大同小异,最优解出现在 (x, y)
点的 上下左右,四个部分,这四个部分都可以抽象成 [单调栈] aw152. 城市游戏(单调栈+最大矩形面积进阶) 这个题,故预处理得到上下左右四个方向的最大矩形面积,然后针对每个查询进行查表即可。
直接计算每一个查询的最大面积,时间复杂度为
O
(
n
2
∗
Q
)
O(n^2*Q)
O(n2∗Q),优化预处理后,就将
Q
Q
Q,优化到
O
(
1
)
O(1)
O(1) 了。故时间复杂度为
O
(
n
2
)
O(n^2)
O(n2),完全可以 AC
本题。
注意:
- 本题在抽象 下左右,的时候值得注意一下这种处理方式,尤其是 左右 部分的时候,压缩连续 1 的个数的时候,循环顺序从 行—列,要变为 列—行。这也是很棒的处理方式!
- 在计算最大矩形面积的时候,只需要数组从 1 开始,数组有效长度即可。在这一步是封装出来的。
本题可以多写几次,很棒的题目。
时间复杂度:
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;
}