LeetCode085 Maximal Rectangle(Not fully understand)

Given a 2D binary matrix filled with 0’s and 1’s, find the largest rectangle containing only 1’s and return its area.
example:
Input:
[
[“1”,“0”,“1”,“0”,“0”],
[“1”,“0”,“1”,“1”,“1”],
[“1”,“1”,“1”,“1”,“1”],
[“1”,“0”,“0”,“1”,“0”]
]
Output: 6

simple dp problem. but the results of following code is not right, and I don’t understand why.

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        int m = matrix.length;
        int n = matrix[0].length;
        
        int[][] maxLeft = new int[m][n]; //maxLeft[i] is the longest left consective number of 1s contains current place
        int[][] maxUp = new int[m][n]; //maxUp[i] is the longest up consective number of 1s contains current place
        //so that why the global maximal of maxLeft[i][j]*maxUp[i][j] will be the final results
        
        if (matrix[0][0] == '1') {
            maxLeft[0][0] = 1;
            maxUp[0][0] = 1;
        } else {
            maxLeft[0][0] = 0;
            maxUp[0][0] = 0;
        }
        
        for (int i = 1; i<n; i++) {
            if (matrix[0][i] == '1') {
                maxLeft[0][i] = maxLeft[0][i-1] + 1;
            } else {
                maxLeft[0][i] = 0;
            }
        }
        
        for (int i = 1; i<m; i++) {
            if (matrix[i][0] == '1') {
                maxUp[i][0] = maxUp[i-1][0] + 1;
            } else {
                maxUp[i][0] = 0;
            }
        }
        
        for (int i = 1; i<m; i++) {
            for (int j = 1; j<n; j++) {
                if (matrix[i][j] == '1') {
                    maxLeft[i][j] = maxLeft[i][j-1] + 1;
                    maxUp[i][j] = maxUp[i-1][j] + 1;
                } else {
                    maxLeft[i][j] = 0;
                    maxUp[i][j] = 0;
                } 
            }
        }
        
        int res = 0;
        for (int i = 0; i < m; i++){
            for (int j = 0; j<n; j++) {
                res = Math.max(res, maxUp[i][j] * maxLeft[i][j]);
            }
        }
        return res;
    }
}

Now, I know why previous code is not right! This entire code is totally wrong!! I only considered the upper and left, but what we really need, is a rectangle filled with 1s.
so situations like:
000100
000100
011100
000000
my code will get the result of 9, but the correct result is 1.
so I rewrite my code, it is still not working:

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        int m = matrix.length;
        int n = matrix[0].length;
        
        int[][] maxLeft = new int[m][n]; //maxLeft[i] is the longest left consective number of 1s contains current place
        int[][] maxUp = new int[m][n]; //maxUp[i] is the longest up consective number of 1s contains current place
        //so that why the global maximal of maxLeft[i][j]*maxUp[i][j] will be the final results
        int[][] dp = new int[m][n];
        int res = 0;
        
        if (matrix[0][0] == '1') {
            maxLeft[0][0] = 1;
            maxUp[0][0] = 1;
            dp[0][0] = 1;
            res = 1;
        } else {
            maxLeft[0][0] = 0;
            maxUp[0][0] = 0;
            dp[0][0] = 0;
        }
        
        for (int i = 1; i<n; i++) {
            if (matrix[0][i] == '1') {
                maxLeft[0][i] = maxLeft[0][i-1] + 1;
            } else {
                maxLeft[0][i] = 0;
            }
        }
        
        for (int i = 1; i<m; i++) {
            if (matrix[i][0] == '1') {
                maxUp[i][0] = maxUp[i-1][0] + 1;
            } else {
                maxUp[i][0] = 0;
            }
        }
        
        for (int i = 1; i<m; i++) {
            for (int j = 1; j<n; j++) {
                if (matrix[i][j] == '1') {
                    maxLeft[i][j] = maxLeft[i][j-1] + 1;
                    maxUp[i][j] = maxUp[i-1][j] + 1;
                } else {
                    maxLeft[i][j] = 0;
                    maxUp[i][j] = 0;
                } 
            }
        }
        
        for (int i = 1; i < m; i++) {
            dp[i][0] = maxUp[i][0] * 1;
            res = Math.max(res, dp[i][0]);
        }
        for (int i = 1; i < n; i++) {
            dp[0][i] = maxLeft[0][i] * 1;
            res = Math.max(res, dp[0][i]);
        }
        
        
        for (int i = 1; i < m; i++){
            for (int j = 1; j<n; j++) {
                if (matrix[i][j] == '1'){
                    if (dp[i-1][j-1] == 0) {
                        dp[i][j] = Math.max(maxUp[i][j], maxLeft[i][j]);
                        
                    } else {
                        dp[i][j] = (Math.min(maxUp[i][j] - 1, maxUp[i-1][j-1]) + 1) * (Math.min(maxLeft[i][j] - 1, maxLeft[i-1][j-1]) + 1);
                    }
                    
                    res = Math.max(res, dp[i][j]);
                }
                
            }
        }
        return res;
    }
}

the following code is accepted, but I’m not fully understand. and the person who thought of this solution says he is inspried by other problems call maximal rectangle in histogram. but I don’t think they are so similiar, at least we only use a ple stack in this solution.

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix.length == 0) return 0;
        int n = matrix[0].length;
        int[] height = new int[n + 1];//只用了一个height数组
        height[n] = 0;
        int res = 0;

        for (int row = 0; row < matrix.length; row++) {//row by row
            Stack<Integer> stack = new Stack<>();
            for (int i = 0; i < n + 1; i++) {//
                if (i < n) { //如果i在matrix里面作为列数是合法的
                    if (matrix[row][i] == '1') {
                        height[i]++; //这里的height[i]就跟俄罗斯方块一样 代表当前此列连续积累的高度
                    } else height[i] = 0;//构建height数组的方式跟上个方法一样
                }
                
                while (!stack.isEmpty() && height[i] < height[stack.peek()]) { //we maintain an element increasing stack, which is the ple of current index
                    int cur = height[stack.pop()] * (stack.isEmpty() ? i : (i - stack.peek() - 1)); //can't fully understand this statement. because, as we known, stack.pop() is the largest in stack, and it's peek() is the second largest. so why do I have to use height[stack.pop()] * (stack.isEmpty() ? i : (i - stack.peek() - 1))? 
                    res = Math.max(res, cur);
                }
                stack.push(i);
                
            }
        }
        return res;
    }
}

and there is a dp solution for this problem:
this solution is much alike the solution in maximal rectangle in histogram.

  • we start from the first row, and move downward;
  • height[i] record the current number of countinous ‘1’ in column i;
  • left[i] record the left most index j which satisfies that for any index k from j to i, height[k] >= height[i]; which is similar to a decrease stack
  • right[i] record the right most index j which satifies that for any index k from i to j, height[k] >= height[i]; which is similiar to a decrease stack
  • by understanding the definition, we can easily figure out we need to update maxArea with value (height[i] * (right[i] - left[i] + 1));

//based on this, we have following code. the code is written by myself, which is exactly the same as the solution provided by others, but it just couldn’t be accepted! WTF?

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) return 0;
        
        int m = matrix.length;
        int n = matrix[0].length;
        int res = 0;
        
        int[] left = new int[n];
        int[] right = new int[n];
        int[] height = new int[n];
        
        Arrays.fill(right, n - 1); //why we have to initialize right will n-1??????????
        
        for (int i = 0; i < m; i++) { //row by row
            int rB = n - 1;
            for (int j = n - 1; j >= 0; j--) {
                if (matrix[i][j] == '1') {
                    right[j] = Math.min(right[j], rB); //due to we need to find the closest right index
                } else { //if the current position has value of 0, which means
                    right[j] = n - 1; //because we have already initialize right with n-1, so we don't necessaily need to write this
                    rB = j - 1;
                }
            }
            int lB = 0;
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '1') {
                    left[j] = Math.max(left[i], lB);
                    
                    height[j]++;
                    res = Math.max(res, height[j] * (right[j] - left[j] + 1));
                } else {
                    left[j] = 0; //not necessary
                    lB = j + 1;
                    
                    height[j] = 0;
                }
            }
            
        }
        return res;
        
    }
}
posted @ 2020-06-08 11:49  EvanMeetTheWorld  阅读(17)  评论(0)    收藏  举报