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