221. Maximal Square
2016-08-18 05:55
375 查看
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:
Return 4
这题跟之前的maximal rectangle乍看是一样的。差别在于一个求最大矩形面积一个求正方形面积。看清楚单词square和rectangle。在rectangle那道题中比较好的做法有预处理后建立新的表格检索处理方法,也有结合一维数组中的最大矩形面积做法的写法。具体的两种方法讨论见链接里另一篇博客。
这里可以直接套用预处理建立表格的方法来做。
这种方法跟maximal rectangle的那种做法如出一辙,给我们提了个预处理的方法。但这题更好更快的做法还是dynamic programming. 因为是正方形,形状固定,之前的矩形有太多可能性,没有直接的递推方法,但正方形可以。
这就有点像之前的棋盘里的各种路径问题了,初始化第一行第一列,然后依次递推。建立的动态表格里,每一个数代表了以这个位置为右下角的最大正方形面积。基本代码如下:
优化一:
当然这种动态规划的题,一般都可以在基础表述上优化,一般也都是在优化内存使用问题。因为需要用的位置只有三个,只占用两列,所以我们可以构造两列数组,滚动存储。代码如下:
优化二:
还可以将内存使用降低到一列!因为如果我们只用一列,那么在更新这一列的时候,这个位置cur[i]原来的值其实就是prev[i], 也就是下一个位置需要的prev[i-1]。再加上cur[i-1]。所以我们用一列也可以记录三个位置的信息,具体代码如下:
这里对dynamic programming的使用对比之前的maximal rectangle来说很有启发,内存上的优化值得大家学习。
square containing only 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
这题跟之前的maximal rectangle乍看是一样的。差别在于一个求最大矩形面积一个求正方形面积。看清楚单词square和rectangle。在rectangle那道题中比较好的做法有预处理后建立新的表格检索处理方法,也有结合一维数组中的最大矩形面积做法的写法。具体的两种方法讨论见链接里另一篇博客。
这里可以直接套用预处理建立表格的方法来做。
方法一:预处理建立表格
对于给出矩阵,建立相同size的数组矩阵,每一位数大小对应从它开始向右检索的连续1的个数。建立矩阵后,依次检索,对于每一个不是0的位置,讨论以它为左上角对应的最大square面积。代码如下:int maximalSquare(vector<vector<char>>& matrix) { int m = matrix.size(); if (m == 0) return 0; int n = matrix[0].size(); vector<vector<int>> res(m, vector<int>(n+1, 0)); int i, j, k; //预处理建立表格,每个数代表以此向右连续的1个数 for (i = 0; i < m; i++) { for (j = n-1; j >=0; j--) { if (matrix[i][j] == '1') res[i][j] = res[i][j+1] + 1; else res[i][j] = 0; } } int maxarea = 0, length = 0; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { //增加预判,如果最大可能都没有,直接跳过 if (res[i][j]*res[i][j] <= maxarea) continue; //该点向下检索,每步更新最小长度,约束k else { length = res[i][j]; for (k = 1; k <= length && (i+k-1) < m; k++) { length = min(length, res[i+k-1][j]); if (length < k) break; //一旦检索行不符合要求,终止 } //记录此时能达到的最大行数,也就是正方形边长 length = k - 1; maxarea = max(maxarea, length*length); } } } return maxarea; }
这种方法跟maximal rectangle的那种做法如出一辙,给我们提了个预处理的方法。但这题更好更快的做法还是dynamic programming. 因为是正方形,形状固定,之前的矩形有太多可能性,没有直接的递推方法,但正方形可以。
方法二:动态规划dynamic programming
基本的递推关系可以表示如下,state equation:P[0][j] = matrix[0][j] (topmost row); P[i][0] = matrix[i][0] (leftmost column); For i > 0 and j > 0: if matrix[i][j] = 0, P[i][j] = 0; if matrix[i][j] = 1, P[i][j] = min(P[i - 1][j], P[i][j - 1], P[i - 1][j - 1]) + 1.
这就有点像之前的棋盘里的各种路径问题了,初始化第一行第一列,然后依次递推。建立的动态表格里,每一个数代表了以这个位置为右下角的最大正方形面积。基本代码如下:
int maximalSquare(vector<vector<char>>& matrix) { int m = matrix.size(); if (m == 0) return 0; int n = matrix[0].size(); vector<vector<int>> res(m, vector<int>(n, 0)); int i, j, k, length = 0; //初始化第一列 for (i = 0; i < m; i++) { res[i][0] = matrix[i][0] - 48< b3bb /span>; length = max(length, res[i][0]); } //初始化第一行 for (j = 0; j < n; j++) { res[0][j] = matrix[0][j] - 48; length = max(length, res[0][j]); } //依次递推 for (i = 1; i < m; i++) { for (j = 1; j < n; j++) { if (matrix[i][j] == '1') { res[i][j] = min(res[i-1][j-1], min(res[i-1][j], res[i][j-1])) + 1; length = max(length, res[i][j]); } else res[i][j] = 0; } } return length*length; }
优化一:
当然这种动态规划的题,一般都可以在基础表述上优化,一般也都是在优化内存使用问题。因为需要用的位置只有三个,只占用两列,所以我们可以构造两列数组,滚动存储。代码如下:
int maximalSquare(vector<vector<char>>& matrix) { int m = matrix.size(); if (m == 0) return 0; int n = matrix[0].size(); vector<int> prev(m, 0); vector<int> cur(m, 0); int i, j, length = 0; //初始化第一列 for (i = 0; i < m; i++) { prev[i] = matrix[i][0] - 48; //注意一定要在边界就更新最大长度,因为可能矩阵里只有边界有1 length = max(length, prev[i]); } for (j = 1; j < n; j++) { //先初始化第一个元素,也是第一行的部分,为递推做准备 cur[0] = matrix[0][j] - 48; length = max(length, cur[0]); for (i = 1; i < m; i++) { if (matrix[i][j] == '1') { cur[i] = min(cur[i-1], min(prev[i-1], prev[i])) + 1; length = max(length, cur[i]); } else cur[i] = 0; } swap(prev, cur); //更新prev,并且将cur归零 fill(cur.begin(), cur.end(), 0); } return length*length; }
优化二:
还可以将内存使用降低到一列!因为如果我们只用一列,那么在更新这一列的时候,这个位置cur[i]原来的值其实就是prev[i], 也就是下一个位置需要的prev[i-1]。再加上cur[i-1]。所以我们用一列也可以记录三个位置的信息,具体代码如下:
int maximalSquare(vector<vector<char>>& matrix) { if (matrix.empty()) return 0; int m = matrix.size(), n = matrix[0].size(); vector<int> dp(m + 1, 0); //因为没有初始化动作,所以长度增加一位,方便直接对第一行的元素计算 int maxsize = 0, pre = 0; for (int j = 0; j < n; j++) { for (int i = 1; i <= m; i++) { //将这个位置更新前信息保存,因为这是下一个位置的prev[i-1],之后便赋值给pre。 int temp = dp[i]; //因为dp最一开始就是全0,所以对第一列并不影响 if (matrix[i - 1][j] == '1') { dp[i] = min(dp[i], min(dp[i - 1], pre)) + 1; maxsize = max(maxsize, dp[i]); } else dp[i] = 0; pre = temp; } } return maxsize * maxsize; }
这里对dynamic programming的使用对比之前的maximal rectangle来说很有启发,内存上的优化值得大家学习。
相关文章推荐
- Convert Binary Search Tree to Doubly Linked List
- 深夜记一个大坑:illegalStateException:can not perform this action after onSaveInstanceState
- Valid Perfect Square
- 递归神经网络 简单示例
- Fast Power
- Print Numbers by Recursion
- MyBatis Generator
- Install and config Redis on Mac OS X via Homebrew
- LeetCode--No.219--Contains Duplicate II--有个地方不太懂
- 【BLE】CC2541之Large OAD
- 文章末页页数
- Ericsson open-sources OpenWebRTC and Bowser for iOS; Intel releases IoT developer kit
- MySQL 体系结构和存储引擎
- seajs 2.x _ 非模块化的调用方式
- struts2 动态Action
- 五险一金
- struts2 入门程序
- Imagination的ClearCall VoIP应用现可支持Cavium的OCTEON III多核处理器
- LeetCode--No.88--Merge Sorted Array
- python--字符编码