LeetCode算法网站的算法题
https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
1.暴力算法:
枚举宽:
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;
}
};
2.单调栈
class Solution
{
public:
int largestRectangleArea(vector<int>& heights)
{
int n = heights.size();
vector<int> left(n)/*left[i]存储第i根柱子左边第一个高度小于第i根柱子的下标,-1为哨兵*/, right(n)/*right[i]存储第i根柱子右边第一个高度小于第i根柱子的下标,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;
}
};
3.单调栈+常数优化
class Solution
{
public:
int largestRectangleArea(vector<int>& heights)
{
int n = heights.size();
vector<int> left(n), right(n, n);
stack<int> mono_stack;
for (int i = 0; i < n; ++i)
{
while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i])
{
right[mono_stack.top()] = i;/*我们在对位置 i 进行入栈操作时,确定了它的左边界。从直觉上来说,与之对应的我们在对位置 i
进行出栈操作时可以确定它的右边界!仔细想一想,这确实是对的。当位置 i 被弹出栈时,说明此时遍历到的位置 i0 的高度小于等于height[i],
并且在 i0 与 i 之间没有其他高度小于等于height[i] 的柱子。这是因为,如果在 i 和 i0 之间还有其它位置的高度小于等于 height[i] 的,
那么在遍历到那个位置的时候,i 应该已经被弹出栈了。所以位置 i0 就是位置 i 的右边界。*/
mono_stack.pop();
}
left[i] = (mono_stack.empty() ? -1 : 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;
}
};