Leetcode:Maximal Rectangle
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode:Maximal Rectangle相关的知识,希望对你有一定的参考价值。
题目大意:给一个由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 }
以上是关于Leetcode:Maximal Rectangle的主要内容,如果未能解决你的问题,请参考以下文章