#leetcode#Maximal Square

来源:互联网 发布:易语言自动刷图源码 编辑:程序博客网 时间:2024/05/16 09:25

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 01 0 1 1 11 1 1 1 11 0 0 1 0
Return 4.

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

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

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

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

1 0 1 0 01 0 1 1 11 1 1 2 21 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数

0 0
原创粉丝点击