85. Maximal Rectangle

题目:

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.

链接: http://leetcode.com/problems/maximal-rectangle/

题解:

题目就比较难理解。我一看containing all ones,直接return 长 x 宽,果断fail了。正确的意思应该是find the largest rectangle containing only ones and return its area。

Brute force  - O(m3 x n3)  遍历整个数组,先找到lower-left,接下来找到upper-right, 然后探测是否只包括1,同时与current best candidate 进行比较。

Region Grow - O(m2 x n2)

DP - O(m2 x n)

下面是用largest histgram的方法来做 - 对每一行cache 元素'1'的个数,当前元素为'0'时清零当前height。之后对每行进行一个"getLargestHistogram" 运算,来得到当前行的最大rectangle结果,最后和global max进行比较。Reference 1里是一个哥们1998年写的文章,就是关于这一题,很详细,为他点个赞学习了。  Heights数组的存在就是cache从row0到当前row为止在row上的1的数目, 每完成一行cache,我们都必须对当前的heights数组,也就是cache的结果进行find largest rectangle in histogram的操作, 否则到下一行的话有可能有些结果就被清零了。相当于computer 一个local max,再尝试去update一个global的max。

 Time Complexity - O(mn), Space Complexity - O(n)。

public class Solution {
    public int maximalRectangle(char[][] matrix) {
        if(matrix == null || matrix.length == 0)
            return 0;
        int max = 0;
        int[] heights = new int[matrix[0].length];
        
        for(int i = 0; i < matrix.length; i++) {            // O(n),  n = matrix.length;
            for(int j = 0; j < matrix[0].length; j++) {     // O(m),  m = matrix[0].length;
                if(matrix[i][j] == '1')                     // cache '1' in historgram array heights[]
                    heights[j]++;
                else
                    heights[j] = 0;
            }
            max = Math.max(max, findLargestRectangleInHistogram(heights));   // for each row, fine max rectangle,  O(m) operation
        }
        
        return max;
    }
    
    private int findLargestRectangleInHistogram(int[] heights) {        // find Larget Rectangle in Histogram
        if(heights == null || heights.length == 0)
            return 0;
        int[] h = new int[heights.length + 1];
        h = Arrays.copyOf(heights, heights.length + 1);
        int i = 0, max = 0;
        Stack<Integer> stack = new Stack<>();
        
        while(i < h.length) {
            if(stack.isEmpty() || h[i] >= h[stack.peek()])
                stack.push(i++);
            else {
                int tmp = stack.pop();
                max = Math.max(max, h[tmp] * (stack.isEmpty() ? i : ((i - 1) - stack.peek())));
            }
        }
        
        return max;
    }
}

  

有的时候不是自己不会做,而是见识太少。绝大部分的面试题都是有踪迹可循,像这道题,或者大整数乘除法,又或者滑雪。所以我认为题海战术是一定有效的。进了公司之后的发展另说,先进入好公司,赶上这波IT繁荣的尾巴,才是目前阶段最重要的。

 

二刷:

刚做完84,所以做85就轻松一些。方法还是跟一刷一样。下面我们理一理思路。

  1. 首先我们明确目的,是要求整个matrix矩阵中,只包含1的最大矩阵。我们可以套用上一题目中,求一个histogram中最大的rectangle的方法。
  2. 我们只需要在按行遍历matrix矩阵的时候,使用一个accumulatedLen矩阵来记录这行的0和1的累积情况。这个想法类似dp和
    1. 假如当前行row[i] = '0',则我们清零accumulatedLen[i]
    2. 否则我们累积每个1, accumulatedLen[i] += 1
  3. 每次计算完一行的accumulatedLen数组时,我们就调用计算largestRectInHistogram的方法,来尝试更新max
  4. 最后返回max

Java:

Time Complexity - O(mn), Space Complexity - O(n)

public class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        int colNum = matrix[0].length;
        int[] accumulatedHeights = new int[colNum];
        int max = 0;
        LinkedList<Integer> list = new LinkedList<>();
        for (char[] row : matrix) {
            list.clear();
            for (int i = 0; i < colNum; i++) {
                accumulatedHeights[i] = row[i] == '0' ? 0 : accumulatedHeights[i] + 1;
            }
            max = Math.max(calcLargestHist(accumulatedHeights, list), max);
        }
        return max;
    }
    
    private int calcLargestHist(int[] heights, LinkedList<Integer> list) {
        if (heights == null || heights.length == 0) {
            return 0;
        }
        int i = 0, max = 0;
        while (i < heights.length) {
            if (list.size() == 0 || heights[i] >= heights[list.peekLast()]) {
                list.addLast(i++);
            } else {
                int lastIndex = list.pollLast();
                max = Math.max(max, heights[lastIndex] * (list.size() == 0 ? i : (i - 1) - list.peekLast()));
            }
        }
        while (list.size() > 0) {
            int lastIndex = list.pollLast();
            max = Math.max(max, heights[lastIndex] * (list.size() == 0 ? i : (i - 1) - list.peekLast()));
        }
        return max;
    }
}

 

三刷:

依然是使用了一刷二刷的办法,利用上一题来求解。然而@morrischen2008的DP方法更为优雅,放在reference里,需要再进一步好好学习。

Java:

Time Complexity - O(mn), Space Complexity - O(mn)

public class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix.length == 0) return 0;
        int colNum = matrix[0].length;
        int[] heights = new int[colNum];
        int max = 0;
        for (char[] row : matrix) {
            for (int j = 0; j < colNum; j++) {
                if (row[j] == '1') heights[j]++;
                else heights[j] = 0;
            }
            max = Math.max(max, getLargestRectangleArea(heights));
        }
        return max;
    }
    
    private int getLargestRectangleArea(int[] heights) {
        if (heights == null || heights.length == 0) return 0;
        Stack<Integer> stack = new Stack<>();
        int max = 0, idx = 0;
        while (idx <= heights.length) {
            int curHeight = (idx != heights.length) ? heights[idx] : 0;
            if (stack.isEmpty() || curHeight >= heights[stack.peek()]) {
                stack.push(idx++);
            } else {
                int height = heights[stack.pop()];
                int len = stack.isEmpty() ? idx : (idx - 1 - stack.peek());
                max = Math.max(max, height * len);
            }
        }
        return max;
    }
}

 

 

测试:

Reference:

http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529

http://www.cnblogs.com/lichen782/p/leetcode_maximal_rectangle.html

https://leetcode.com/discuss/20240/share-my-dp-solution

https://leetcode.com/discuss/5198/a-o-n-2-solution-based-on-largest-rectangle-in-histogram

https://leetcode.com/discuss/52670/solution-based-maximum-rectangle-histogram-with-explanation

https://leetcode.com/discuss/97731/solution-largest-rectangle-histogram-solved-stack-simulation

 

posted @ 2015-04-18 12:05  YRB  阅读(734)  评论(0编辑  收藏  举报