題目連接:https://leetcode.com/problems/largest-rectangle-in-histogram/description/ide
題目大意:在直方圖中找出最大的矩形面積。例子以下:優化
法一:暴力,無任何優化,超時了。對於每一個高度,分別向左和向右查找能到達的最遠下標(在目前的高度狀況下)。代碼以下:spa
1 public int largestRectangleArea(int[] heights) { 2 int ma = 0; 3 for(int i = 0; i < heights.length; i++) { 4 //向左 5 int left = i; 6 for(; left >= 0 && heights[left] >= heights[i]; left--); 7 //向右 8 int right = i; 9 for(; right < heights.length && heights[right] >= heights[i]; right++); 10 int sum = (right - left - 1) * heights[i]; 11 if(sum > ma) { 12 ma = sum; 13 } 14 } 15 return ma; 16 }
法二:換了一種思惟方式的暴力,依舊超時。再也不從中間向兩邊擴展,而是每到一個點,就找其局部峯值,而後由局部峯值點向前查找每一個矩形面積,比較得最大值。代碼以下:code
1 public int largestRectangleArea(int[] heights) { 2 int ma = 0; 3 for(int i = 0; i < heights.length; i++) { 4 //找局部峯值 5 //若是不是目前峯值,則跳過 6 if(i + 1 < heights.length && heights[i] < heights[i + 1]) { 7 continue; 8 } 9 //若是是目前峯值,則向前計算矩形,會將目前峯值前面全部可能的矩形面積都計算一遍 10 //因此雖然這個方法沒有在每一個點上向左右兩邊擴展計算全部可能的矩形面積,可是其實也變相計算了全部可能的矩形面積,只是換了種思惟方式 11 int mi = heights[i]; 12 for(int j = i; j >= 0; j--) { 13 mi = Math.min(mi, heights[j]); 14 int sum = mi * (i - j + 1); 15 ma = Math.max(ma, sum); 16 } 17 } 18 return ma; 19 }
法三:用stack優化暴力,其實也計算了全部可能的矩形面積,只是優化了遍歷方式,聽說時間複雜度是o(n)?比較懷疑。代碼以下(耗時23ms):blog
1 public int largestRectangleArea(int[] heights) { 2 //stack中存遞增高度 3 Stack<Integer> s = new Stack<Integer>(); 4 int ma = 0; 5 for(int i = 0; i < heights.length; i++) { 6 //若是棧頂高度比當前高度高,則退棧 7 //由目前棧頂高度向右計算可能的最大矩形面積,其實最終也把每一個點全部可能的矩形面積都計算了一遍,可是因爲優化計算,效率上好了不少 8 while(!s.isEmpty() && heights[s.peek()] >= heights[i]) { 9 int cur = s.pop(); 10 //計算矩形面積 11 ma = Math.max(ma, heights[cur] * (s.isEmpty() ? i : (i - s.peek() - 1))); 12 } 13 //若是與棧頂是遞增關係,則壓棧 14 s.push(i); 15 } 16 //因爲最後stack中一定存在一個遞增序列,由於在最後一次s.push(i)以後,沒有計算,因此要將此遞增序列計算完 17 while(!s.isEmpty()) { 18 int cur = s.pop(); 19 ma = Math.max(ma, heights[cur] * (s.isEmpty() ? heights.length : (heights.length - s.peek() - 1))); 20 } 21 return ma; 22 }