1. 程式人生 > 其它 >單調棧解決leetcode-84柱狀圖中最大的矩形

單調棧解決leetcode-84柱狀圖中最大的矩形

思路: 比如當前柱子的高度是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); } }