在柱狀圖中找最大矩形——O(n)時間複雜度java實現
阿新 • • 發佈:2019-02-10
最近在刷leetcode,又碰到了這道題,想起來當時演算法有些瑕疵,所以將最新的AC程式碼更新在最上面做個對比,具體思路見註釋.
public class Solution { // 思路: 主要是使用一個棧來儲存陣列元素的下標,注意是儲存‘下標’。 // 入棧和出棧的規則如下: // (1) 當棧為空,或者以棧頂元素tp為下標查到的heights[tp] <= heights[i]時(i為當前遍歷的索引),入棧 // (2) 當棧頂元素tp對應的heights[tp] > heights[i]時,出棧,同時計算以heights[tp]為高,能得到的最大矩形面積 // (3) 當遍歷完整個heights陣列後,若棧不為空,則依次彈棧,同時以棧頂元素tp對應的heights[tp]為高,計算能得到的最大矩形面積 public int largestRectangleArea(int[] heights) { if (heights == null || heights.length == 0) { return 0; } Stack<Integer> stack = new Stack<Integer>(); int maxSize = 0; int i = 0; for (; i < heights.length; i++) { if (stack.empty() || heights[stack.peek()] <= heights[i]) { stack.push(i); } else { // 當前遍歷元素heights[i] 比棧頂元素tp對應的heights[tp]小, 棧頂元素出棧 int tp = stack.pop(); int beginIndex = stack.empty() ? -1 : stack.peek(); // 當棧為空時,說明最大矩形的長度從下標0開始 // 所以將beginIndex設定為-1 maxSize = max(maxSize, heights[tp] * (i-1 - beginIndex)); i--; // 由於heights[i]元素還在棧外等候,還需要繼續和棧頂元素進行比較,所以i-- } } while (!stack.empty()) { // 棧還不為空,對每個棧頂元素tp 計算以heights[tp]為高的矩形的最大面積, 並將棧頂元素出棧 int tp = stack.pop(); int beginIndex = stack.empty() ? -1 : stack.peek(); // 當棧為空時,說明最大矩形的長度從下標0到下標n-1, // 所以將beginIndex設定為-1 maxSize = max(maxSize, heights[tp] * (i-1 - beginIndex)); } return maxSize; } private int max(int a, int b) { return a > b ? a : b; } }
這次沒有bug了 :)
@2016-03-07
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
最近在準備找工作,知道了這道題,用java實現了O(n)時間複雜度的演算法。
具體題目如下:給一組非負的整數來表示一個柱狀圖,設計一個演算法獲得柱狀圖中最大矩形的面積。比如,輸入如下資料:2,1,4,5,1,3,3 ,其中每個數表示一個柱狀條的高度,柱狀條的寬度為預設值1,則計算得最大矩形的面積為8。
思路:使用一個棧來儲存輸入柱狀條,每個柱狀條包含兩個資訊:(1)柱狀條的高度(height);(2)柱狀條的x座標(index) 。陣列中的柱狀條按序準備入棧,入棧的條件:當入棧元素e的高度>=棧頂元素的高度時,元素e入棧;否則,將棧頂元素出棧,同時更新最大矩形maxValue的值。
更新maxValue的演算法如下:
1. 計算以當前棧頂元素的高度為寬度的矩形的面積:tmpValue = topElement.height * (e.index - topElement.index);
2. 更新maxValue: maxValue = (maxValue > tmpValue) ? maxValue : tmpValue;
所有元素入棧完畢,將棧中剩餘的元素依次出棧,同時按照相同的思路更新maxValue的值。
java實現:
演算法分析:import java.util.ArrayList; import java.util.List; import java.util.Stack; public class MaxRectangle { // 使用棧來儲存每個柱狀條,噹噹前準備入棧的柱狀條的高度小於當前棧頂的柱狀條高度時,先讓棧頂元素出棧,同時計算最大的矩形大小 public int maxRectangleValue(int[] array) { if (array == null || array.length <= 0) return -1; int maxValue = 0; List<Element> inputList = new ArrayList<Element>(); int len = array.length; for (int i = 0; i < len; i++) { Element element = new Element(array[i], i); inputList.add(element); } // 開始入棧操作 Stack<Element> stack = new Stack<Element>(); for (Element e : inputList) { if (stack.empty()) stack.add(e); else { while (e.height < stack.peek().height) { // 出棧,並計算最大矩形大小 Element topElement = stack.pop(); int tmpValue = topElement.height * (e.index - topElement.index); // height * width if (tmpValue > maxValue) maxValue = tmpValue; if (stack.empty()) break; } // 進棧 stack.add(e); } } // 將堆疊中包含的所有元素出棧,同時更新最大的矩形大小 while (!stack.empty()) { Element topElement = stack.pop(); int tmpValue = topElement.height * ((len - 1) - topElement.index + 1); // height * width if (tmpValue > maxValue) maxValue = tmpValue; } return maxValue; } public static void main(String[] args) { int[] array = {2,1,4,5,1,3,3}; MaxRectangle mr = new MaxRectangle(); System.out.println(mr.maxRectangleValue(array)); } } class Element { public int height; // 每一個柱狀條的高度(寬度為1) public int index; // 每個柱狀條的x座標值,代表它們出現的相對次序 public Element(int height, int index) { this.height = height; this.index = index; } }
所有陣列元素需要一次進棧和一次出棧,所以總的時間複雜度為:O(n)