在看到题的时候,先看看数据的范围
n <= 4:任何时间复杂度的算法都可以用
n <= 1000: 需要考虑O(n^2) / O(n^2logn)的算法才可以
n <= 50000:需要考虑O(nlogn) O(nlog^2n), O(n)的算法
首先想到蛮力算法
底是从lo到hi的,那么底为hi - lo + 1
高就是lo到hi之间最低的高度
因此我们枚举每一个底边,计算出高,并找到最大的面积
思路:枚举每一个底边,再在这个范围里面找到高
时间复杂度O(n^3)
具体代码(蛮力算法)
class Solution {
public:
//蛮力算法
int largestRectangleArea(vector<int>& heights) {
int ans(0);
for (int lo(0); lo < heights.size(); lo++) {
for (int hi(lo); hi < heights.size(); hi++) {
int width = hi - lo + 1;
int height(50000);
//Error1: 在寻找loca的时候忽略了lo == hi的情况
for (int loca = lo; loca <= hi; loca++) {
height = min(height, heights[loca]);
}
ans = max(ans, width * (height));
}
}
return ans;
}
};
蛮力算法的一种改进
我们发现,在枚举底边的时候,就可以顺带把最低的高度求出来了,其实就是利用了最低高度在一定范围内的不变性
具体算法(蛮力算法的一种优化),时间复杂度O(n^2)
class Solution {
public:
//蛮力算法的一种优化
int largestRectangleArea(vector<int>& heights) {
int ans(0);
for (int lo(0); lo < heights.size(); lo++) {
int height(50000);
for (int hi(lo); hi < heights.size(); hi++) {
int width = hi - lo + 1;
height = min(height, heights[hi]);
ans = max(ans, width * (height));
}
}
return ans;
}
};
我们或许可以使用栈这种数据结构进行优化,个人认为算法思路还是找卡点,因为栈是单增的,所以遍历的过程就是在找右卡点。
维护一个单调栈(栈底到栈顶高度单调上升)
根据下一个需要插入的列和当前栈顶位置高度的关系
弹出栈并更新答案
将该列压入栈
代码如下(单调栈解法)
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
if (heights.empty()) {
return 0;
} else {
//完成哨兵的插入
heights.insert(heights.begin(), 0);
heights.insert(heights.end(), 0);
}
int ans(0);
stack<int> Stack = stack<int>();
//Error2:先将哨兵压入
Stack.push(0);
//Error3:a的范围应该是< heights.size() - 1
for (int a(1); a <= heights.size() - 1; a++) {
//当前元素比栈顶元素小的时候,进行答案的更新
while (heights[a] < heights[Stack.top()]) {
//Error4:栈里面的都是位置
int height = heights[Stack.top()];
Stack.pop();
ans = max(ans, (a - Stack.top() - 1) * height);
}
Stack.push(a);
}
return ans;
}
};