题目:84. 柱状图中最大的矩形 - 力扣(LeetCode)
第一反应是找每个柱子两边比它小的最近的柱子。继续不按套路出牌,找一种更好理解的解法:
从数据规模看,O(nlogn)的解法也可以。
- 我们可以对柱子由高到低排个序,排序时不要丢失每个柱子的原始位置
- 建立一个数组f,每个元素是一个范围,表示当前柱子为范围的边缘时,最左和最右柱子的位置。初始值都设为-1
struct F { int l = -1; int r = -1; };
- 由高到低逐步插入一个数组里,位置就是柱子的原始位置idx
- 如果idx-1的l不为-1,则f[idx-1].l到idx的位置可以练成一片;右侧亦然
- 每次插入都可以用O(1)的时间计算出左右最大联通的范围,柱子的高度*范围就是以当前柱子的高度为高时,idx所在矩形的最大面积
struct Node {
int idx;
int value;
};
struct F {
int l = -1;
int r = -1;
};
bool myComp(Node& a, Node& b) {
return a.value > b.value;
}
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
vector<Node> arr(n);
vector<F> f(n);
for (int i = 0; i < n; i++) {
arr[i].idx = i;
arr[i].value = heights[i];
}
sort(arr.begin(), arr.end(), myComp);
int ret = 0;
int idx;
int s;
for (int i = 0; i < n; i++) {
const Node& node = arr[i];
idx = node.idx;
f[idx].l = idx;
f[idx].r = idx;
if (idx > 0 && f[idx - 1].l != -1) {
f[idx].l = f[idx - 1].l;
}
if (idx < n - 1 && f[idx + 1].r != -1) {
f[idx].r = f[idx + 1].r;
}
f[f[idx].l].r = f[idx].r;
f[f[idx].r].l = f[idx].l;
s = node.value * (f[idx].r + 1 - f[idx].l);
if (s > ret) ret = s;
}
return ret;
}
};