1. 程式人生 > >Leetcode:Maximal Rectangle

Leetcode:Maximal Rectangle

open top private pro ray 數組 最大 所有 gif

  題目大意:給一個由0和1組成r行c列的矩陣M,找出其中面積最大的由1組成的矩形。  

  這道題目和之前一道提供高度計算最大矩形的題目Largest Rectangle in Histogram是一樣的,這裏也一塊說一下。Largest Rectangle in Histogram這道題目提供若幹寬度為1的柱形,求其中最大的矩形面積,柱形由高度和位置唯一決定,由一個數組H表示,H[i]表示編號為i的柱形的高度。

  顯然如果一個矩形最大,那麽其必定包含一個高度最低的柱形,設其下標為i。假設矩形的左右邊界矩形的下標為a+1和b-1,那麽必然有H[a]<H[i]和H[b]<H[i],否則矩形可以進一步擴大,與其最大這一前提相悖。對於每一個柱形H[i],利用左右邊界的性質可以決定唯一的最大矩形候選,而只要挑選出所有矩形候選中面積最大者,就是我們需要的結果。下面稍微說明一下如何在O(n)時間內找到每一個最大矩形候選的右邊界。從0到n遍歷整個H,將所有未找到右邊界的柱形加入到一個棧結構中。顯然棧中的柱形高度應該是遞增的。每次遇到一個新的柱形,將棧中所有高度比其小的柱形全部彈出並設置右邊界為新柱形,最後將新柱形加入到棧中。等到遍歷結束,就將所有棧中剩余的柱形的右邊界設置為n(因為剩余的都是沒有匹配到右邊界的)。同理可以利用類似的思路得到所有矩形候選的左邊界。這兩個過程的時間復雜度都是O(n)(因為每一個柱形只入棧和出棧各一次,共n個柱形)。有了左右邊界計算面積就很容易了,可以在O(n)的時間復雜度內完成。

  因此對於上面的這種問題我們始終能在O(n)的時間復雜度內解決。

  現在說明如何解決Maximal Rectangle這道題目。首先我們可以將矩陣的第0行到第i行理解為一個柱形圖,且第j列的高度為M[i][j],M[i-1][j],...,M[0][j]中只包含1的最長前綴的長度。可以通過動態規劃得到第i行第j列的高度H[i][j],因為H[i][j] = 1 == M[i][j] ? H[i-1][j] + 1 : 0。這樣我們要找面積最大的只由1組成的矩形等價於找r個柱形圖中最大的矩形,每個柱形圖通過Largest Rectangle in Histogram的方法可以在O(c)時間內計算得到,故總時間為O(rc),加上動態規劃所花費的O(rc)的時間,因此總的時間復雜度為O(rc)。

  下面上代碼:

技術分享
 1 class Solution {
 2     public int maximalRectangle(char[][] matrix) 
 3     {
 4         if(matrix.length == 0 || matrix[0].length == 0)
 5         {
 6             return 0;
 7         }
 8         int h = matrix.length;
 9         int w = matrix[0].length;
10         int[] heights = new int
[w]; 11 int max = 0; 12 for(int i = 0; i < h; i++) 13 { 14 char[] row = matrix[i]; 15 for(int j = 0; j < w; j++) 16 { 17 heights[j] = row[j] == ‘0‘ ? 0 : heights[j] + 1; 18 } 19 max = Math.max(max, theLargestArea(heights)); 20 } 21 return max; 22 } 23 24 public int theLargestArea(int[] heights) 25 { 26 int n = heights.length; 27 int[] leftLower = new int[n]; 28 int[] rightLower = new int[n]; 29 30 IntStack stk = new IntStack(n + 1); 31 for(int i = 0; i < n; i++) 32 { 33 int h = heights[i]; 34 while(stk.size() > 0 && heights[stk.peek()] > h) 35 { 36 rightLower[stk.pop()] = i; 37 } 38 stk.push(i); 39 } 40 while(stk.size() > 0) 41 { 42 rightLower[stk.pop()] = n; 43 } 44 45 for(int i = n - 1; i >= 0; i--) 46 { 47 int h = heights[i]; 48 while(stk.size() > 0 && heights[stk.peek()] > h) 49 { 50 leftLower[stk.pop()] = i; 51 } 52 stk.push(i); 53 } 54 while(stk.size() > 0) 55 { 56 leftLower[stk.pop()] = -1; 57 } 58 59 int max = 0; 60 for(int i = 0; i < n; i++) 61 { 62 int area = (rightLower[i] - leftLower[i] - 1) * heights[i]; 63 max = Math.max(max, area); 64 } 65 66 // System.out.println(Arrays.toString(heights) + " : " + max); 67 return max; 68 } 69 70 private static class IntStack{ 71 int[] arr; 72 int top = 0; 73 public IntStack(int capacity) 74 { 75 arr = new int[capacity]; 76 } 77 public void push(int val) 78 { 79 arr[top++] = val; 80 } 81 public int pop() 82 { 83 return arr[--top]; 84 } 85 public int peek() 86 { 87 return arr[top - 1]; 88 } 89 public int size(){ 90 return top; 91 } 92 } 93 }
View Code

  

Leetcode:Maximal Rectangle