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;
}