Leetcode—221.Maximal Square 最大正方形

来源:互联网 发布:视频马赛克复原软件 编辑:程序博客网 时间:2024/05/18 20:12

问题描述:

Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 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.

概括一下就是,给一个二维char数组,元素只有‘0’和‘1’,我们需要找一个最大只有‘1’组成的正方形注意只能是正方形,不能是矩形


解题思路:

一看到一个二维数组,总会让我联想到DP的二维数组,因此我就考虑能不能用DP来做。假设m[ i ][ j ]表示该位置作为右下角能组成的最大正方形的边长,我们考虑当前问题的最优解可以将它转化成什么样的子问题最优解集合。

我们可以考虑m[ i-1][ j-1 ],m[ i-1][ j ],m[ i ][ j-1 ]三个位置,结合图可以得到,当前位置的最优解:如果当前位置为‘0’,那么最优解就是0;如果当前位置不为‘0’,最优解m[ i ][ j ]  就等于:

 1. m[ i-1][ j-1 ]的半径   

 2. 从当前位置向上延伸(所在列 j 向上)连续的‘1’的个数,以及  

 3. 当前位置左侧延伸(所在行 i 向左)连续‘1’的个数,

这三个数中最小值+1.


一开始我每次找每个点解得时候,总是将2.3两个条件从 j-1 到 0 以及 从 i-1 到 0 遍历找连续 ‘1’ 的个数,结果不幸的超时了。

后来我又专门开了两个同样的二维数组left[][]和up[][]来保存连续1的个数,虽然A掉不超时了,但是牺牲空间换时间,导致我凭空多的两个二维数组的空间,看起来总是不爽……

然后我们需要再好好结合图来分析下我们的问题了:

假设我们m[ i-1][ j-1 ],m[ i-1][ j ],m[ i ][ j-1 ]表示三个位置三个值,他们都不相同。这个时候我们m[ i ][ j ] 最优解为多少呢?其实,应该是:

m[ i ][ j ]  = min( m[ i-1][ j-1 ],min( m[ i-1][ j ],m[ i ][ j-1 ] ) );

m[ i-1][ j-1 ],m[ i-1][ j ],m[ i ][ j-1 ] 代表了m[ i ][ j ]正方形边缘的范围,而m[ i-1][ j-1 ]决定了m[ i ][ j ]正方形内部填充的范围。

仔细理解下这句话,画个图你就会明白的。我直接上代码了:

class Solution {public:    int maximalSquare(vector<vector<char>>& m) {        if(m.empty() || m[0].empty()) return 0;        char res = '0';        for(int i = 0; i<m.size(); i++)            for(int j = 0; j<m[0].size(); j++){                if(m[i][j] == '1'){                    if(i&&j) m[i][j] = min(m[i][j-1], min(m[i-1][j], m[i-1][j-1]))+1;                    res = max(m[i][j], res);                  }            }        return (res-'0')*(res-'0');    }};

由于是char的数组,我就直接用char计数了,可能数据维度大会越界,安全性考虑的话可以换成int。目前跑的没问题。

时间复杂度O(M*N),空间复杂度为O(1), 在Leetcode上是 6ms。