Maximal Rectangle -- LeetCode

原题链接:  http://oj.leetcode.com/problems/maximal-rectangle/  
这是一道非常综合的题目,要求在0-1矩阵中找出面积最大的全1矩阵。刚看到这道题会比较无从下手,brute force就是对于每个矩阵都看一下,总共有m(m+1)/2*n(n+1)/2个子矩阵(原理跟字符串子串类似,字符串的子串数有n(n+1)/2,只是这里是二维情形,所以是两个相乘),复杂度相当高,肯定不是面试官想要的答案,就不继续想下去了。
这道题的解法灵感来自于 Largest Rectangle in Histogram 这道题,假设我们把矩阵沿着某一行切下来,然后把切的行作为底面,将自底面往上的矩阵看成一个直方图(histogram)。直方图的中每个项的高度就是从底面行开始往上1的数量。根据 Largest Rectangle in Histogram 我们就可以求出当前行作为矩阵下边缘的一个最大矩阵。接下来如果对每一行都做一次 Largest Rectangle in Histogram ,从其中选出最大的矩阵,那么它就是整个矩阵中面积最大的子矩阵。
算法的基本思路已经出来了,剩下的就是一些节省时间空间的问题了。
我们如何计算某一行为底面时直方图的高度呢? 如果重新计算,那么每次需要的计算数量就是当前行数乘以列数。然而在这里我们会发现一些动态规划的踪迹,如果我们知道上一行直方图的高度,我们只需要看新加进来的行(底面)上对应的列元素是不是0,如果是,则高度是0,否则则是上一行直方图的高度加1。利用历史信息,我们就可以在线行时间内完成对高度的更新。我们知道, Largest Rectangle in Histogram 的算法复杂度是O(n)。所以完成对一行为底边的矩阵求解复杂度是O(n+n)=O(n)。接下来对每一行都做一次,那么算法总时间复杂度是O(m*n)。
空间上,我们只需要保存上一行直方图的高度O(n),加上 Largest Rectangle in Histogram 中所使用的空间O(n),所以总空间复杂度还是O(n)。代码如下:
[java]  view plain copy
  1. public int maximalRectangle(char[][] matrix) {  
  2.     if(matrix==null || matrix.length==0 || matrix[0].length==0)  
  3.     {  
  4.         return 0;  
  5.     }  
  6.     int maxArea = 0;  
  7.     int[] height = new int[matrix[0].length];  
  8.     for(int i=0;i<matrix.length;i++)  
  9.     {  
  10.         for(int j=0;j<matrix[0].length;j++)  
  11.         {  
  12.             height[j] = matrix[i][j]=='0'?0:height[j]+1;  
  13.         }  
  14.         maxArea = Math.max(largestRectangleArea(height),maxArea);  
  15.     }  
  16.     return maxArea;  
  17. }  
  18. public int largestRectangleArea(int[] height) {  
  19.     if(height==null || height.length==0)  
  20.     {  
  21.         return 0;  
  22.     }  
  23.     int maxArea = 0;  
  24.     LinkedList<Integer> stack = new LinkedList<Integer>();  
  25.     for(int i=0;i<height.length;i++)  
  26.     {  
  27.           
  28.         while(!stack.isEmpty() && height[i]<=height[stack.peek()])  
  29.         {  
  30.             int index = stack.pop();  
  31.             int curArea = stack.isEmpty()?i*height[index]:(i-stack.peek()-1)*height[index];  
  32.             maxArea = Math.max(maxArea,curArea);  
  33.         }  
  34.         stack.push(i);  
  35.     }  
  36.     while(!stack.isEmpty())  
  37.     {  
  38.         int index = stack.pop();  
  39.         int curArea = stack.isEmpty()?height.length*height[index]:(height.length-stack.peek()-1)*height[index];  
  40.         maxArea = Math.max(maxArea,curArea);              
  41.     }  
  42.     return maxArea;  
  43. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值