單調棧主要用於處理,在連續數據結構中(數組)快速獲取比自己大或者小的數字索引。
比如下題中的需求
由於是求左邊比當前元素大的最近的元素。
我們使用棧記錄之前的數字索引和大小,棧頂是離當前元素最近的,如果它不符合條件,那麼我們接下來只需要繼續向左檢測,且檢測比已經檢測的元素更大的元素(某個元素不符合條件,小於等於它的元素無須檢測)。那麼這個棧排除了過小的元素,棧裏的元素肯定是從棧頂到棧底,呈現一個單調的趨勢,如圖
地址 https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
給定 n 個非負整數,用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰,且寬度爲 1 。
求在該柱狀圖中,能夠勾勒出來的矩形的最大面積。
示例 1:
輸入:heights = [2,1,5,6,2,3]
輸出:10
解釋:最大的矩形爲圖中紅色區域,面積爲 10
示例 2:
輸入: heights = [2,4]
輸出: 4
提示:
1 <= heights.length <=10^5
0 <= heights[i] <= 10^4
解答
如果暴力枚舉每個邊作爲矩形的高去計算能組成的矩形,時間複雜度是O(n^2),會超時。
但是如果我們使用單調棧記錄每個邊左邊與右邊比當前邊最近的短的邊,就可以得出它能組成的矩形長度。時間複雜度是O(n)
代碼如下
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int> st;
int n = heights.size();
int left[100010]; int right[100010];
memset(left, -1, sizeof left);
memset(right, -1, sizeof right);
for (int i = 0; i < heights.size(); i++) {
while (!st.empty() && heights[st.top()] >= heights[i]) st.pop();
if (st.empty()) left[i] = 0;
else left[i] = st.top()+1;
st.push(i);
}
st = stack<int>();
for (int i = heights.size() - 1; i >= 0; i--) {
while (!st.empty() && heights[st.top()] >= heights[i]) st.pop();
if (st.empty()) right[i] = n -1;
else right[i] = st.top()-1;
st.push(i);
}
int ans = -1;
for (int i = 0; i < heights.size(); i++) {
if (left[i] == -1) left[i] = 0;
if (right[i] == -1) right[i] = heights.size()-1;
int area = heights[i] * (right[i] - left[i]+1);
ans = max(ans, area);
}
return ans;
}
};