題目鏈接
84. 柱狀圖中最大的矩形
題目描述
解題思路
暴力法
對於每一個高度height[i],我們可以向左向右遍歷,然後算出該高度往左往右最多可以延申至何處,這樣就能算出該高度對應的面積,枚舉所有高度然後求出最大值。
時間複雜度:O(n)
空間複雜度:O(1)
超時!
單調棧
以上暴力寫法 Java 可以通過,但我們不妨想一下這裏的雙重循環是否可以優化?
我們每遍歷到當前柱體 i 時:暴力解法中我們需要再嵌套一層 while 循環來向左找到第一個比柱體 i 高度小的柱體,這個過程是 O(N) 的;
那麼我們可以 O(1)的獲取柱體 i 左邊第一個比它小的柱體嗎?答案就是單調增棧,因爲對於棧中的柱體來說,棧中下一個柱體就是左邊第一個高度小於自身的柱體。
因此做法就很簡單了,我們遍歷每個柱體,若當前的柱體高度大於等於棧頂柱體的高度,就直接將當前柱體入棧,否則若當前的柱體高度小於棧頂柱體的高度,說明當前棧頂柱體找到了右邊的第一個小於自身的柱體,那麼就可以將棧頂柱體出棧來計算以其爲高的矩形的面積了。
小trick:爲長度數組首位加上兩個0,便於計算,同時可以解決高度遞增序列現象問題。
AC代碼
暴力法
class Solution {
public int largestRectangleArea(int[] heights) {
int area = 0, n = heights.length;
// 遍歷每個柱子,以當前柱子的高度作爲矩形的高 h,
// 從當前柱子向左右遍歷,找到矩形的寬度 w。
for (int i = 0; i < n; i++) {
int w = 1, h = heights[i], j = i;
while (--j >= 0 && heights[j] >= h) {
w++;
}
j = i;
while (++j < n && heights[j] >= h) {
w++;
}
area = Math.max(area, w * h);
}
return area;
}
}
單調棧法
class Solution {
public int largestRectangleArea(int[] heights) {
int ans = 0;
int cHeights[] = new int[heights.length+2];
cHeights[0] = 0;
cHeights[heights.length+1] = 0;
for(int i = 1; i < heights.length+1; i++){
cHeights[i] = heights[i-1];
}
Stack<Integer> st = new Stack<>();
for(int i = 0; i < cHeights.length; i++){
while(!st.isEmpty() && cHeights[i] < cHeights[st.peek()]){
int height = cHeights[st.pop()];
ans = Math.max(ans,height * (i - st.peek() - 1));
}
st.push(i);
}
return ans;
}
}