思路
用到了單調棧。由於最大矩形它的高一定是height陣列中的其中一個值,那麼我們就可以遍歷陣列height的值再乘上它的寬的最大值WidthMax(寬的最大值後面會講),然後取最大值就是答案,也就是ans=max(ans,WidthMax*height[x])。
那麼如何求高為height[x]的寬的最大值WidthMax呢?
解題過程
如圖,以黃色塊為高所能撐起的最大範圍即為紅色部分,(陣列heigh中的每個值都有可能是黃色塊,所以後面要遍歷一下)那麼問題就轉變為:
1.求從x開始的左邊找第一個高度小於heigh[x]的長方形的下標l
2.同理,求從x的右邊第一個小於heigh[x]的長方形的下標r
3.矩形的寬的最大值為WidhMax = r -l -1
那麼問題又轉變為如何求上面的l和r?
對於求r,此問題不就是已知陣列的下標,求該下標開始從右邊開始找第一個更小值嗎?此時就可以用單調棧的思想來預處理每個點的右邊界的值了,該過程與力扣中https://leetcode.cn/problems/next-greater-element-i/description/這道題相似,不懂單調棧的可以先做那道題
那麼l也同理,從左邊開始找第一個更小值的下標
那麼r[x]和l[x]就求出來了,
最後遍歷每個小長方形,求(height[x]*(r[x]-l[x]-1))的最大值就是答案了
時間複雜度: 𝑂(𝑛)
空間複雜度: 𝑂(𝑛)
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
//選定一個下標,從這個下標兩邊分別找第一個比它矮的下標(理解為找左邊的第一個更小數,右邊的第一個更小數),然後r-l-1個這樣的矩形的和即為答案的可能之一
const int N = 1e5+50;
int l[N], r[N], s[N],top = -1;
//預處理每個點的兩邊第一次碰到更矮的下標
for(int i = 0; i < heights.size(); i++){
int num = heights[i];
while(top>=0&&heights[s[top]]>=num){
top--;
}
if(top>=0)
l[i] = s[top];
else l[i] = -1;
s[++top]=i;
}
top = -1;
for(int i = heights.size()-1; i >= 0; i--){
int num = heights[i];
while(top>=0 && heights[s[top]] >= num)
top--;
if(top>=0) r[i] = s[top];
else r[i] = heights.size();
s[++top] = i;
}
int ans = 0;
for(int i = 0; i < heights.size(); i++){
ans = max(ans,(r[i]-l[i]-1)*heights[i]);
}
return ans;
}
};