單調棧解決leetcode-84柱狀圖中最大的矩形
阿新 • • 發佈:2021-12-20
思路:
比如當前柱子的高度是h,這個問題的本質就是分別算出當前柱子左右兩側,第一個小於h柱子的位置,左側leftMin如果比0小就是-1,右側rightMin比索引大就是index+1·,最後當前柱子的最大面積就是(rightMin-leftMin-1)*h,然後比較每個柱子的最大柱子,得到最終結果。
首先最先想到的是暴力法,根據兩層迴圈遍歷,算出每個柱子的最大面積。
單調棧法:
首先補充下單調棧的概念:
從棧尾到棧頂遞減就是單調遞減棧;
從棧尾到棧懂遞增就是單調遞增棧。
單調遞增棧,可以找到左右兩邊第一個比他小的元素;
單調遞減棧,可以找到左右兩邊第一個比他大的元素。
對於每個元素,其有且僅有一次插入,最多出現一次刪除,故其時間複雜度為O(n)。
當元素出棧時,說明這個新元素是出棧元素向後找第一個比其小的元素
用單調遞增棧解決當前問題,因為要找出左右兩側第一個比他小的元素的位置。遍歷到一個元素的時候,如果當前棧不為空,就比較棧頂元素和當前元素i的大小,如果i比棧頂小,那棧頂元素就是右側第一個比i小的元素,彈出棧頂元素,最後棧為空或者當前元素大於棧頂元素就跳出迴圈;判斷棧是否為空,為空說明當前元素左側沒有比他小的,不為空就是棧頂是右側第一個比他小的元素。最後棧中還剩資料,說明這些元素的右側沒有比他小的。
對於棧裡的元素來說,當前準備入棧的元素就是他們右側,如果有元素彈出,當前準備入棧的元素就是彈出元素右側第一個比他小的;
對於準備入棧的元素來說,棧裡的元素就是他的左側,如果在當前元素入棧的時候棧為空,說明左側沒有比他小的,如果棧不為空,棧裡都是比他小的元素,那麼棧頂就是右側第一個比他小的元素。
一次遍歷就可以拿到每個位置左右兩側第一個比他小元素的索引。
題目:
給定 n 個非負整數,用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰,且寬度為 1 。
求在該柱狀圖中,能夠勾勒出來的矩形的最大面積。
解答:
public class LargestRectangleArea_84 {
public static int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
int[] right = new int[n];
Deque<Integer> stack = new ArrayDeque<Integer>();
for(int i=0;i<heights.length;i++) {
//單調遞增棧,找出右邊第一個小於當前元素的值
//把陣列索引存在stack中,當棧不為空且當前棧頂的節點小於當前陣列時候,
//入棧的時候,如果棧為空,說明他的左側沒有比當前入棧位置要小的元素,左側比他小的位置就是-1,
//如果棧中有元素的時候,棧頂的數就是左側第一個比他小的數
while(!stack.isEmpty()&&heights[stack.peek()]>heights[i]) {
right[stack.pop()]=i;
}
//判斷棧是否為空,為空說明當前元素左側沒有比他小的,不為空就是棧頂是右側第一個比他小的元素。
left[i]=stack.isEmpty()?-1:stack.peek();
stack.push(i);
}
//棧中還剩資料,說明棧中資料右側沒有比他小的,全部填充為陣列長度
while(!stack.isEmpty()) {
right[stack.pop()]=heights.length;
}
int max=0;
for(int i=0;i<left.length;i++) {
max=Math.max(max, (right[i]-left[i]-1)*heights[i]);
}
return max;
}
public static void main(String[] args) {
int[] array= {6, 7, 5, 2, 4, 5, 9, 3};
largestRectangleArea(array);
}
}