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.

Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.

这道题我刚看到的时候,马上联想到了之前的一道 Number of Islands,但是仔细一对比,发现又不太一样,那道题1的形状不确定,很适合 DFS 的特点,而这道题要找的是正方形,是非常有特点的形状,所以并不需要用到 DFS,要论相似,我倒认为这道 Maximal Rectangle 更相似一些。这道题的解法不止一种,我们先来看一种 brute force 的方法,这种方法的机理就是就是把数组中每一个点都当成正方形的左顶点来向右下方扫描,来寻找最大正方形。具体的扫描方法是,确定了左顶点后,再往下扫的时候,正方形的竖边长度就确定了,只需要找到横边即可,这时候我们使用直方图的原理,从其累加值能反映出上面的值是否全为1,之前也有一道关于直方图的题 Largest Rectangle in Histogram。通过这种方法我们就可以找出最大的正方形,参见代码如下:

解法一:

class Solution {
public:
int maximalSquare(vector<vector<char> >& matrix) {
int res = ;
for (int i = ; i < matrix.size(); ++i) {
vector<int> v(matrix[i].size(), );
for (int j = i; j < matrix.size(); ++j) {
for (int k = ; k < matrix[j].size(); ++k) {
if (matrix[j][k] == '') ++v[k];
}
res = max(res, getSquareArea(v, j - i + ));
}
}
return res;
}
int getSquareArea(vector<int> &v, int k) {
if (v.size() < k) return ;
int count = ;
for (int i = ; i < v.size(); ++i) {
if (v[i] != k) count = ;
else ++count;
if (count == k) return k * k;
}
return ;
}
};

下面这个方法用到了建立累计和数组的方法,可以参见之前那篇博客 Range Sum Query 2D - Immutable。原理是建立好了累加和数组后,我们开始遍历二维数组的每一个位置,对于任意一个位置 (i, j),我们从该位置往 (0,0) 点遍历所有的正方形,正方形的个数为 min(i,j)+1,由于我们有了累加和矩阵,能快速的求出任意一个区域之和,所以我们能快速得到所有子正方形之和,比较正方形之和跟边长的平方是否相等,相等说明正方形中的数字均为1,更新 res 结果即可,参见代码如下:

解法二:

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

我们还可以进一步的优化时间复杂度到 O(n2),做法是使用 DP,建立一个二维 dp 数组,其中 dp[i][j] 表示到达 (i, j) 位置所能组成的最大正方形的边长。我们首先来考虑边界情况,也就是当i或j为0的情况,那么在首行或者首列中,必定有一个方向长度为1,那么就无法组成长度超过1的正方形,最多能组成长度为1的正方形,条件是当前位置为1。边界条件处理完了,再来看一般情况的递推公式怎么办,对于任意一点 dp[i][j],由于该点是正方形的右下角,所以该点的右边,下边,右下边都不用考虑,关心的就是左边,上边,和左上边。这三个位置的dp值 suppose 都应该算好的,还有就是要知道一点,只有当前 (i, j) 位置为1,dp[i][j] 才有可能大于0,否则 dp[i][j] 一定为0。当 (i, j) 位置为1,此时要看 dp[i-1][j-1], dp[i][j-1],和 dp[i-1][j] 这三个位置,我们找其中最小的值,并加上1,就是 dp[i][j] 的当前值了,这个并不难想,毕竟不能有0存在,所以只能取交集,最后再用 dp[i][j] 的值来更新结果 res 的值即可,参见代码如下:

解法三:

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

下面这种解法进一步的优化了空间复杂度,此时只需要用一个一维数组就可以解决,为了处理边界情况,padding 了一位,所以 dp 的长度是 m+1,然后还需要一个变量 pre 来记录上一个层的 dp 值,我们更新的顺序是行优先,就是先往下遍历,用一个临时变量t保存当前 dp 值,然后看如果当前位置为1,则更新 dp[i] 为 dp[i], dp[i-1], 和 pre 三者之间的最小值,再加上1,来更新结果 res,如果当前位置为0,则重置当前 dp 值为0,因为只有一维数组,每个位置会被重复使用,参见代码如下:

解法四:

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

类似题目:

Maximal Rectangle

Largest Rectangle in Histogram

参考资料:

https://leetcode.com/problems/maximal-square/

https://leetcode.com/problems/maximal-square/discuss/61803/c-dynamic-programming

https://leetcode.com/problems/maximal-square/discuss/61913/my-concise-solution-in-c

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Maximal Square 最大正方形的更多相关文章

  1. [LintCode] Maximal Square 最大正方形

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

  2. 【动态规划】leetcode - Maximal Square

    称号: Maximal Square Given a 2D binary matrix filled with 0's and 1's, find the largest square contain ...

  3. [LeetCode] 221. Maximal Square 最大正方形

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

  4. LeetCode Maximal Square

    原题链接在这里:https://leetcode.com/problems/maximal-square/ 这是一道DP题,存储历史信息是到当前点能有的最大square, 用二维数组dp存储. 更新方 ...

  5. [LeetCode] Valid Square 验证正方形

    Given the coordinates of four points in 2D space, return whether the four points could construct a s ...

  6. 221 Maximal Square 最大正方形

    在一个由0和1组成的二维矩阵内,寻找只包含1的最大正方形,并返回其面积.例如,给出如下矩阵:1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0返回 4. 详见:https://l ...

  7. Leetcode221. Maximal Square最大正方形

    在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积. 示例: 输入: 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 输出: 4 方法一 ...

  8. 求解最大正方形面积 — leetcode 221. Maximal Square

    本来也想像园友一样,写一篇总结告别 2015,或者说告别即将过去的羊年,但是过去一年发生的事情,实在是出乎平常人的想象,也不具有代表性,于是计划在今年 6 月份写一篇 "半年总结" ...

  9. leetcode每日解题思路 221 Maximal Square

    问题描述: 题目链接:221 Maximal Square 问题找解决的是给出一个M*N的矩阵, 只有'1', '0',两种元素: 需要你从中找出 由'1'组成的最大正方形.恩, 就是这样. 我们看到 ...

随机推荐

  1. 介介介是一个ORM

    介个是一个ORM,介个ORM基于Dapper扩展. 为什么需要一个ORM呢? 支持简单的LINQ查询 但是不能连表查询,why?why?why?为什么不能连接查询 ^.^ ok.但是就是不支持.哈哈哈 ...

  2. Google地图开发总结

    我们经常使用地图查位置.看公交.看街景,同时地图还开放第三方的API给开发者.利用这些API进行地图的个性化的展示和控制,例如北京被水淹了,开发一个网页显示北京被淹的地图,地图上面标志被水淹的位置.严 ...

  3. 使用命令 gradle uploadArchives 的异常: Unable to initialize POM pom-default.xml: Failed to validate POM for project

    在使用:gradle uploadArchives 命令对项目进行上传maven时,常常遇到如下报错: 这时候要仔细的检查一下build.gradle文件中的dependencies内容,很多时候是由 ...

  4. Javaweb项目框架搭建-准备篇

    前言Java从大二开始学习到现在大四也有差不多两年了,但是由于之前一直在玩,没有认真学过,直到现在才开始重新学习.也是很凑巧,看到了黄勇老师的<架构探险>,于是便开始学习写Java Web ...

  5. 高效 Java Web 开发框架 JessMA v3.5.1

    JessMA 是功能完备的高性能 Full-Stack Web 应用开发框架,内置可扩展的 MVC Web 基础架构和 DAO 数据库访问组件(内部已提供了 Hibernate.MyBatis 与 J ...

  6. JQuery中$.ajax()方法参数详解

    url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. type: 要求为String类型的参数,请求方式(post或get)默认为get.注意其他http请求方法,例如put和 ...

  7. Httpster –世界各地最潮的网页设计案例聚合网站

    Httpster 这个网站聚合了世界各地最新最潮的网页设计案例,展示了创意的设计,精心的策划,优秀的排版.这些作品都按月份和类别进行了很好划分,你可以方便的找到自己感兴趣的网站案例. 立即去看看 您可 ...

  8. 基于SAP的中国式数据分析浅谈

    大数据时代,虽然多数企业数据的应用并不能称得上是“大数据”,但也证实了数据应用的重要性和影响力.确实,数据作为企业发展的信息沉淀,已成为企业的重要资产,如何有效利用数据是每个企业必须面临的课题. 这里 ...

  9. iOS通知的整理笔记

    iOS通知用于高耦合界面的传值确实方便快捷. 需要实现模态弹出的视图控制器上,有一个视图控制器可以导航.这必定要将这个视图控制器的导航视图控制器naVC.view添加到模态弹出的视图控制器presen ...

  10. UIMenuItem

    UIMenuItem *share = [[UIMenuItem alloc] initWithTitle:@"分享"action:@selector(shareClick:)]; ...