单调栈的经典应用场景是,在一维数组中,对每一个数字,找到前/后面第一个比自己大/小的元素。
该题的思路是:
对数组中的每个元素,若假定以它为高,能够展开的宽度越宽,那么以它为高的矩形面积就越大。
因此,思路就是找到每个元素左边第一个比它矮的矩形和右边第一个比它矮的矩形,在这中间的就是最大宽度
最后对每个元素遍历一遍找到最大值即可。
以上的思路是暴力解法的思路,但可以通过使用单调栈来简化搜索的过程。
力扣官方题解一 使用对数组使用两次单调栈,分别从左向右,从右向左寻找每个元素 第一个 比自己更小的元素,并且巧妙的借助了 -1 和 heights.size(),这两个下标来处理数组单调递增或者递减的情况
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
vector<int> left(n), right(n);
stack<int> mono_stack;
for (int i = 0; i < n; ++i) {
while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) {
mono_stack.pop();
}
left[i] = (mono_stack.empty() ? -1 : mono_stack.top());
mono_stack.push(i);
}
mono_stack = stack<int>();
for (int i = n - 1; i >= 0; --i) {
while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) {
mono_stack.pop();
}
right[i] = (mono_stack.empty() ? n : mono_stack.top());
mono_stack.push(i);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
};
代码随想录这道题则为数组前后插入一个 0 元素,从而巧妙的对单调递增数组和单调递减数组进行处理
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int result = 0;
stack<int> st;
heights.insert(heights.begin(), 0);
heights.push_back(0);
st.push(0);
for (int i = 1; i < heights.size(); i++) {
if (heights[i] > heights[st.top()]) {
st.push(i);
} else if (heights[i] == heights[st.top()]) {
st.pop();
st.push(i);
} else {
while (!st.empty() && heights[i] < heights[st.top()]) {
int mid = st.top();
st.pop();
if (!st.empty()) {
int left = st.top();
int right = i;
int w = right - left - 1;
int h = heights[mid];
result = max(result, w * h);
}
}
st.push(i);
}
}
return result;
}
};