1. 题意
给定一个数组,求以数组中某一元素为高形成的连续矩形的最大面积。
转换成数学的描述就是
给定一个数组,求
a
[
i
:
j
]
m
a
x
(
m
i
n
{
a
[
i
]
,
a
[
i
+
1
]
⋯
,
a
[
j
]
}
×
(
j
−
i
+
1
)
)
a[i:j]\\ max(min\{a[i],a[i+1]\cdots,a[j]\} \times(j-i+1))
a[i:j]max(min{a[i],a[i+1]⋯,a[j]}×(j−i+1))
2. 题解
一个新的思路是,以数组中的某一元素进行扩展。
我们要找的即是,它左边第一个小于它高度的位置,和右边第一个小于它高度的位置。
只是这时刚好用到了数据结构单调栈而已。
- 自己的解
实际上就是把两步合成了一步。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
stack<pair<int,int>> q;
vector<int> left_first_min(n, -1);
vector<int> right_first_min(n, n);
q.push({0, heights[0]});
for (int i = 1; i < n; ++i) {
while (!q.empty() && q.top().second > heights[i]) {
right_first_min[q.top().first] = i;
q.pop();
}
if (q.empty() || q.top().second < heights[i]) {
if (!q.empty()){
left_first_min[i] = q.top().first;
}
}
else {
left_first_min[i] = left_first_min[q.top().first];
}
q.push({i,heights[i]});
}
int ans = 0;
for (int i = 0; i < n; ++i) {
int tot = heights[i] * (right_first_min[i] -
left_first_min[i] - 1);
ans = max(ans, heights[i] *
(right_first_min[i] - left_first_min[i] - 1));
}
return ans;
}
};
- 官解
从左往右扫找到左边第一个小于它的位置;
从右往左扫找到右边第一个小于它的位置。
class Solution {
public:
int largestRectangleArea(vector<int>& heights)
{
int n = heights.size();
vector<int> left(n, -1);
vector<int> right(n, n);
stack<int> p;
for (int i = 0; i < n; ++i) {
while (!p.empty() && heights[i] <= heights[p.top()]) {
p.pop();
}
if (!p.empty())
left[i] = p.top();
p.push(i);
}
p = stack<int>();
for (int i = n - 1; ~i; --i) {
while (!p.empty() && heights[i] <= heights[p.top()])
p.pop();
if (!p.empty())
right[i] = p.top();
p.push(i);
}
// for (int i = 0; i < n; ++i) {
// std::cout << "l:" <<left[i] << "r:" << right[i] << std::endl;
// }
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
};
官方还提供了两种暴力的方式,即枚举宽度和高度
- 枚举区间
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
int ans = 0;
// 枚举左边界
for (int left = 0; left < n; ++left) {
int minHeight = INT_MAX;
// 枚举右边界
for (int right = left; right < n; ++right) {
// 确定高度
minHeight = min(minHeight, heights[right]);
// 计算面积
ans = max(ans, (right - left + 1) * minHeight);
}
}
return ans;
}
};
- 枚举高度
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
int ans = 0;
for (int mid = 0; mid < n; ++mid) {
// 枚举高
int height = heights[mid];
int left = mid, right = mid;
// 确定左右边界
while (left - 1 >= 0 && heights[left - 1] >= height) {
--left;
}
while (right + 1 < n && heights[right + 1] >= height) {
++right;
}
// 计算面积
ans = max(ans, (right - left + 1) * height);
}
return ans;
}
};