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 }
View Code

 

  

 

以上是关于Leetcode:Maximal Rectangle的主要内容,如果未能解决你的问题,请参考以下文章

[LeetCode] Maximal Square

LeetCode Maximal Square

[Leetcode] maximal rectangle 最大矩形

Leetcode:Maximal Rectangle

实验三

wpf中的倒影效果实现