[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 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;
}
};
类似题目:
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] 221. Maximal Square 最大正方形的更多相关文章
- 求解最大正方形面积 — leetcode 221. Maximal Square
本来也想像园友一样,写一篇总结告别 2015,或者说告别即将过去的羊年,但是过去一年发生的事情,实在是出乎平常人的想象,也不具有代表性,于是计划在今年 6 月份写一篇 "半年总结" ...
- (medium)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 ...
- 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 ...
- Leetcode 221. Maximal Square
本题用brute force超时.可以用DP,也可以不用. dp[i][j] 代表 以(i,j)为右下角正方形的边长. class Solution(object): def maximalSquar ...
- Java for 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 ...
- [LeetCode] 221. Maximal Square _ Medium Tag: Dynamic Programming
Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and re ...
- leetcode每日解题思路 221 Maximal Square
问题描述: 题目链接:221 Maximal Square 问题找解决的是给出一个M*N的矩阵, 只有'1', '0',两种元素: 需要你从中找出 由'1'组成的最大正方形.恩, 就是这样. 我们看到 ...
- 【刷题-LeetCode】221. Maximal Square
Maximal Square Given a 2D binary matrix filled with 0's and 1's, find the largest square containing ...
- 【LeetCode】221. Maximal Square
Maximal Square Given a 2D binary matrix filled with 0's and 1's, find the largest square containing ...
随机推荐
- POJ 3041 Asteroids(二分图最大匹配)
###题目链接### 题目大意: 给你 N 和 K ,在一个 N * N 个图上有 K 个 小行星.有一个可以横着切或竖着切的武器,问最少切多少次,所有行星都会被毁灭. 分析: 将 1~n 行数加入左 ...
- tensorflow之tf.squeeze()
tf.squeeze()函数的作用是从tensor中删除所有大小(szie)是1的维度. 给定丈量输入, 此操作返回的是相同类型的张量, 并删除所有尺寸为1的维度.如果不想删除所有尺寸为1的维度, 可 ...
- 【题解】Ples [COCI2011]
[题解]Ples [COCI2011] 依旧是没有传送门,只有提供了数据的官网. [题目描述] \(N\) 个汉子和 \(N\) 个妹纸一起参加舞会,跳舞时只能是一个汉子一个妹纸配对,现在给出每个人的 ...
- 从零开始实现放置游戏(六)——实现后台管理系统(4)Excel批量导入
前面我们已经实现了在后台管理系统中,对配置数据的增删查改.但每次添加只能添加一条数据,实际生产中,大量数据通过手工一条一条添加不太现实.本章我们就实现通过Excel导入配置数据的功能.这里我们还是以地 ...
- px与em的区别
PX特点:px像素(Pixel).相对长度单位.像素px是相对于显示器屏幕分辨率而言的.EM特点 1. em的值并不是固定的:2. em会继承父级元素的字体大小.
- php报错Array to string conversion 解决方案,动态输出数据库列名称
php报错Array to string conversion 解决方案,动态输出数据库列名称 问题:在Windows php5.3环境下使用:<?php echo $row->$keys ...
- opencv::分水岭图像分割
分水岭分割方法原理 (3种) - 基于浸泡理论的分水岭分割方法 (距离) - 基于连通图的方法 - 基于距离变换的方法 图像形态学操作: - 腐蚀与膨胀 - 开闭操作 分水岭算法运用 - 分割粘连对象 ...
- 电信NBIOT 5 - NB73模块下行测试(自己平台-电线平台-NB73)
电信NBIOT 1 - 数据上行(中国电信开发者平台对接流程) 电信NBIOT 2 - 数据上行(中间件获取电信消息通知) 电信NBIOT 3 - 数据下行 电信NBIOT 4 - NB73模块上行测 ...
- Fundebug 微信小游戏异常监控插件更新至 0.5.0,支持监控 HTTP 慢请求
摘要: 支持监控 HTTP 慢请求,同时修复了记录的 HTTP 响应时间偏小的 BUG. Fundebug是专业微信小游戏 BUG 监控服务,可以第一时间捕获线上环境中小游戏的异常.错误或者 BUG, ...
- SQL server 无法更新标识列
若是数据库设置了自增长字段,相应的Model也要做标记,否则修改数据的时候会提示无法更新条目 /// <summary> /// 自增长ID /// </summary> [D ...