#leetcode#Maximal Square

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

For example, given the following matrix:

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 4.

做完这题最大的收获就是加深了对动态规划省空间的理解。

参考这里的解法点击打开链接

题目要求求面积, 面积是由周长决定的,首先建立一个二维数组,int【】【】dp ,dp[i][j]的值对应的是matrix【i】【j】位置上所对应的点能构成的最大正方形的边长,

对应上图得到的dp【】【】结果为

1 0 1 0 0
1 0 1 1 1
1 1 1 2 2
1 0 0 1 0
用一个变量track dp【】【】的最大值 2, 得到最大面积为 2 * 2.

matrix的第一行和第一列是可以初始化对应dp二维数组的,如果有1的话, 则可以构成边长为1的正方形, matrx中的0对应到dp都是0,

对于 i > 1, j > 1(假设都在界内), 则能否构成正方形要看 当前元素 matrix[i][j]  的左边节点, 上边节点, 和左上角的节点, 如果这三个点中有一个是0, 而当前点是1, 则dp[i][j] = 1, 如果这三个点都不为0, 则dp[i][j] = math.min(dp[i][j - 1],dp[i - 1][j], dp[i - 1][j -1]) + 1. 因为边长又多了1, 这个公式对于三点中有0,当前值是1同样适用。

对应代码:

public class Solution {
    public int maximalSquare(char[][] matrix) {
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
            return 0;
        }
        
        int[][] dp = new int[matrix.length][matrix[0].length];
        int maxLen = 0;
        for(int i = 0; i < matrix.length; i++){
            dp[i][0] = Character.getNumericValue(matrix[i][0]);
            if(dp[i][0] > maxLen){
                maxLen = dp[i][0];
            }
        }
        for(int i = 0; i < matrix[0].length; i++){
            dp[0][i] = Character.getNumericValue(matrix[0][i]);
            if(dp[0][i] > maxLen){
                maxLen = dp[0][i];
            }
        }
        for(int i = 1; i < matrix.length; i++){
            for(int j = 1; j < matrix[0].length; j++){
                if(matrix[i][j] == '0'){
                    dp[i][j] = 0;
                }else{
                    // dp[i][j] = Math.min(Math.min(Character.getNumericValue(matrix[i][j - 1]), Character.getNumericValue(matrix[i - 1][j])), Character.getNumericValue(matrix[i - 1][j - 1])) + 1;
                    dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
                    if(dp[i][j] > maxLen){
                        maxLen = dp[i][j];
                    }
                }
            }
        }
        
        return maxLen * maxLen;
    }
}

这里有一个地方我疏忽了, 给的matrix是 char【】【】, 想当然的认为成了int【】【】。。。


然后想到优化这个dp, 因为你每次更新dp值的时候只需要知道当前行前一列的值, 前一行的当前值, 以及前一行的前一列的值, 即

dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]
所以用两个一位数组分别记录当前行和前一行的值就可以了。
</pre></p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 10px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 30px;">对应代码:</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 10px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 30px;"><pre name="code" class="java">public class Solution {
    public int maximalSquare(char[][] matrix) {
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
            return 0;
        }
        
        int[] dp = new int[matrix[0].length];
        int maxLen = 0;
        // for(int i = 0; i < matrix.length; i++){
        //     dp[i][0] = Character.getNumericValue(matrix[i][0]);
        //     if(dp[i][0] > maxLen){
        //         maxLen = dp[i][0];
        //     }
        // }
        
        // int tmpPre = 0;  本来是想用一个变量来存储 top-left 的值, 其实可以用另一个二维数组来存上一排的信息, 这样两个一位数组就可以了, 也是一种空间的优化。
        int[] pre = new int[matrix[0].length];
        for(int i = 0; i < matrix[0].length; i++){
            dp[i] = Character.getNumericValue(matrix[0][i]);
            pre[i] = dp[i];
            if(dp[i] > maxLen){
                maxLen = dp[i];
            }
        }
        
        
        
        for(int i = 1; i < matrix.length; i++){
            for(int j = 0; j < matrix[0].length; j++){
                
                if(j == 0){
                    dp[j] = Character.getNumericValue(matrix[i][j]); 
                    if(dp[j] > maxLen){
                        maxLen = dp[j];
                    }
                }else{
                    if(matrix[i][j] == '0'){
                        dp[j] = 0;
                    }else{
                        dp[j] = Math.min(Math.min(dp[j], dp[j - 1]), pre[j - 1]) + 1;
                        if(dp[j] > maxLen){
                            maxLen = dp[j];
                        }
                    }   
                }
            }
            // set curRow dp[] as pre[], so in the next row we still have the info of the cur row.
            for(int k = 0; k < dp.length; k++){
                pre[k] = dp[k];
            }
        }
        
        return maxLen * maxLen;
    }
}


想了很久怎么用一个变量来代替 pre这个一位数组, 其实每次对新的一行扫描时, 把dp【j】用一个变量tmp存起来, 然后到当前行下一列的时候这个tmp就是dp【i - 1】【j - 1】了, 因为在整个一行的for loop 进行之前, dp【j】中存的值都是上一行的值, 

代码如下:

public class Solution {
    public int maximalSquare(char[][] matrix) {
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
            return 0;
        }
        
        int[] dp = new int[matrix[0].length];
        int maxLen = 0;
       
        int lastPre = 0;
        
        for(int i = 0; i < matrix[0].length; i++){
            dp[i] = Character.getNumericValue(matrix[0][i]);
            if(dp[i] > maxLen){
                maxLen = dp[i];
            }
        }
        
        
        for(int i = 1; i < matrix.length; i++){
            for(int j = 0; j < matrix[0].length; j++){
                int tmp = dp[j];
                if(j == 0){
                    dp[j] = Character.getNumericValue(matrix[i][j]); 
                    if(dp[j] > maxLen){
                        maxLen = dp[j];
                    }
                }else{
                    if(matrix[i][j] == '0'){
                        dp[j] = 0;
                    }else{
                        dp[j] = Math.min(Math.min(dp[j], dp[j - 1]), lastPre) + 1;
                        if(dp[j] > maxLen){
                            maxLen = dp[j];
                        }
                    } 
                }
                
                lastPre = tmp;
            }
        }
        
        return maxLen * maxLen;
    }
}

时间复杂度都是O(m*n), 因为每个点都扫一遍, 空间复杂度从O(m*n)优化到O(2n), 最后是O(n), n为column数

你可能感兴趣的:(LeetCode)