Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.

Example:

Input:
[
["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]
]
Output: 6

思路

看了下discussion,真的很难理解这题的解法。首先还是来慢慢分析吧,对于矩阵中所有可能由1构成的矩形,不管是哪个,它都有个左上顶点,并且这个顶点处的值一定是1,不能是0否则构成不了矩阵。那么反过来推,从行开始一行行从左到右遍历所有可能的左上顶点,如果遇到了1,那么可以知道这个1是可以作为矩形左上顶点的,只不过和它对应的矩形有多个,那么分析这些矩阵的形成规律。

1. 如果是和这个左上顶点在同一行的矩形,那么只能是在这一行往右边临接的点为1的方向延伸,如果遇到了0则表明到达了这个矩阵的右边界,这个0的前一个点(值一定是1)则是这个矩形的右顶点,这是在同一行方向上延伸的分析,矩形的宽就是右顶点的列索引减去左上顶点的列索引,高度则是1。计算完成后,继续遍历矩阵下个左上顶点时会发生重复计算,因为这个左上顶点可能包含在之前算的矩形中。

2. 如果矩形往左上顶点的下一行延伸,那么可以和前面的所有行构成新的矩形,并且这个矩形还可以再往右边延伸,但可以肯定的是这个延伸的矩形的宽不会超过在当前左上顶点行往右延伸的宽度,也就是1中所得出的宽。随着延伸到的每一行,矩形的高度在递增,但是每一行延伸到右边顶点和当前的左上顶点所构成的宽增减规律不明。和1一样的,因为在这之后的遍历左上顶点会包含在当前计算的矩形中,所以也会产生重复计算。

3. 综合1和2,其实都是:

  按行遍历矩阵中所有顶点,值为1则为可能的矩形左上顶点,从当前行从上往下延伸(邻接点是1才可延伸),每到一行(包括当前行)计算往右能够延伸的宽度,当前行能够延伸的最大宽度受制于它上面所有行能够延伸的宽度中最小的那一个,但是上面的行不受下面的行的影响。整个构造不同的矩形过程中,矩形的高度不断增加但是宽度变化不定。因为矩形会包含下次我们要遍历的左上顶点,所以可能会产生重复计算,要避免重复计算,同时不能漏算任何一个可能的最左上顶点。

感觉上面分析得有不对的地方,可以参考这篇博文:https://www.cnblogs.com/grandyang/p/4322667.html

综合分析,构造不同的矩形时有相互依赖制约关系再上可能产生的重复计算,尝试采用dp来解决。

基于以上分析,每个矩形的计算必须要有的三个变量是最左位置,最右位置,以及高度。dp模型如下,上面的分析略有不同:

left(i,j) = max(left(i-1,j), cur_left), cur_left can be determined from the current row,点 matrix[i][j] 所在的矩形的最左边

right(i,j) = min(right(i-1,j), cur_right), cur_right can be determined from the current row,点 matrix[i][j] 所在的矩形的最右边

height(i,j) = height(i-1,j) + 1, if matrix[i][j]=='1'; 点 matrix[i][j] 所在的矩形的高

height(i,j) = 0, if matrix[i][j]=='0'

上面的dp是遍历矩阵所有点(这次不是作为左上顶点了,而是作为一般点),求这个点所在的矩形的最左和最右以及往下探的高,随着往下行延伸,矩形的最左和最右也会发生变化。核心计算思想和之前的分析类似,总体来说就是从单个点开始延伸构造符合条件的矩形,求其面积,感觉和trap wter 以及柱状图那题类似,有种逆向思维的感觉,不从矩形去考虑点,反而从点去考虑矩形这样。

因为上面的索引 j 几乎没什么作用,所以省略掉j,将dp模型简化如下:

left[i]: the index of leftmost '1' in the current group (containing element i ) in this row.
right[i]: the index of rightmost '1' plus one in the current group (containing element i ) in this row.
height[i]: the depth of consecutive ones in this column.

代码

    public int maximalRectangle(char[][] matrix) {
if(matrix.length == 0) {
return 0;
}
int m = matrix.length;
int n = matrix[0].length; int[] left = new int[n]; int[] right = new int[n]; int[] height = new int[n];
//fill right with n, no need to fill left, height since int[] is 0 by default
Arrays.fill(right, n);
int maxArea = 0;
for(int i=0; i<m; i++) { //一行行往下计算(延伸)
int currLeft = 0;
int currRight = n;
//compute height
for(int j=0; j<n; j++) {
if(matrix[i][j] == '1') {
height[j]++;
} else {
height[j] = 0;
}
}
//compute left boundary, currLeft-包含当前行第j个点的矩形的最左。下探到这一行的这个点时,原矩形的最左和currLeft中较大的一个才是新构成的矩形的最左
for(int j=0; j<n; j++) {
if(matrix[i][j] == '1') {
left[j] = Math.max(left[j], currLeft);
} else {
left[j] = 0;
currLeft = j+1;
}
}
//compute right boundary
for(int j=n-1; j>=0; j--) {
if(matrix[i][j] == '1') {
right[j] = Math.min(right[j], currRight);
} else {
right[j] = n;
currRight = j;
}
}
//compute area
for(int j=0; j<n; j++) {
maxArea = Math.max(maxArea, (right[j]-left[j])*height[j]);
}
} return maxArea;
}

算法要点:

1. currRight 和 currLeft 记录的始终是与当前 j 相对应的最左位置和最右位置,就是在这一行的。要拿这两个和之前行的 j 位置去比(left[j], right[j])才能得到新的left[j]和right[j]。

2. 因为是从左到右计算left[j]和从右到左计算right[j],而currLeft初始为0,currRight初始为n,所以当matrix[i][j]不是0是维持原来的currLeft和currRight即可,如果当前的j位置matrix[i][j]是0,因为在j之前的都已计算过currLeft,所以直接将currLeft置为j+1即为后面的数相对应的最左。同时因为matrix[i][j]是0了,构不成矩阵,所以将left[j]置0.

上面是dp的解法,有点复杂,其实这题可以看成是Largest Rectangle in Histogram的扩展,一个n行的二维矩阵,可以看成是多个直方图,每一层到矩阵的顶都是个直方图,输入矩阵有多少行,就可以形成多少个直方图,对每个直方图都调用Largest Rectangle in Histogram 直方图中最大的矩形 中的方法,就可以得到最大的矩形面积。

参考:https://blog.csdn.net/doc_sgl/article/details/11832965

   https://www.cnblogs.com/grandyang/p/4322667.html

LeetCode解题报告—— Maximal Rectangle的更多相关文章

  1. leetcode面试准备: Maximal Rectangle

    leetcode面试准备: Maximal Rectangle 1 题目 Given a 2D binary matrix filled with 0's and 1's, find the larg ...

  2. LeetCode解题报告:Linked List Cycle && Linked List Cycle II

    LeetCode解题报告:Linked List Cycle && Linked List Cycle II 1题目 Linked List Cycle Given a linked ...

  3. leetcode解题报告(2):Remove Duplicates from Sorted ArrayII

    描述 Follow up for "Remove Duplicates": What if duplicates are allowed at most twice? For ex ...

  4. LeetCode 解题报告索引

    最近在准备找工作的算法题,刷刷LeetCode,以下是我的解题报告索引,每一题几乎都有详细的说明,供各位码农参考.根据我自己做的进度持续更新中......                        ...

  5. 【LeetCode】85. Maximal Rectangle

    Maximal Rectangle Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle conta ...

  6. 【leetcode】85. Maximal Rectangle(单调栈)

    Given a rows x cols binary matrix filled with 0's and 1's, find the largest rectangle containing onl ...

  7. 【LeetCode】85. Maximal Rectangle 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/maximal- ...

  8. LeetCode解题报告—— Minimum Window Substring && Largest Rectangle in Histogram

    1. Minimum Window Substring Given a string S and a string T, find the minimum window in S which will ...

  9. 【一天一道LeetCode】#85. Maximal Rectangle

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

随机推荐

  1. Kippo蜜罐的部署、诱捕节点的搭建以及自动告警

    Kippo是一个中等交互的SSH蜜罐,提供了一个可供攻击者操作的shell,攻击者可以通过SSH登录蜜罐,并做一些常见的命令操作. 当攻击者拿下一台服务器的权限后,很可能会进行小范围的端口探测或者批量 ...

  2. Vue项目搭建过程

    环境搭建:mac+nodejs+npm #安装node.js : $ brew install node #安装vue-cil: $ npm install -g vue-cli 注:官网下载安装no ...

  3. 2016多校联合训练1 D题GCD (ST表+二分)

    暑假颓废了好久啊...重新开始写博客 题目大意:给定10w个数,10w个询问.每次询问一个区间[l,r],求出gcd(a[l],a[l+1],...,a[r])以及有多少个区间[l',r']满足gcd ...

  4. ContestHunter暑假欢乐赛 SRM 08

    rating再次跳水www A题贴HR题解!HR智商流选手太强啦!CYC也好强%%%发现了len>10大概率是Y B题 dp+bit优化,据LLQ大爷说splay也可以优化,都好强啊.. C题跑 ...

  5. bzoj2165: 大楼(倍增floyd)

    题目大意:一个有向图,n(<=100)个点求一条长度>=m(<=10^18)的路径最少经过几条边. 一开始以为是矩乘,蓝鹅当时还没开始写,所以好像给CYC安利错了嘿嘿嘿QWQ 第一眼 ...

  6. cmder 添加到右键菜单

    管理员权限打开cmde 输入: cmder /register all 回车,OK

  7. mapper中的CDATA标签的用法

    术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data). 在 XML 元素中,"<" 和 "&& ...

  8. Parcelable序列化对象

    一.序列化的目的 永久性保存对象,保存对象的字节序列到本地文件中: 通过序列化对象在网络中传递对象: 通过序列化在进程间传递对象; 在Intent中进行传递复杂自定义类对象时,需要实现Parcelab ...

  9. 耗子学Python了(2)__Python开发“Hello World”

    一:开发工具 在网上看到的用的开发工具Aptana Studio,我下载的是Aptana_Studio_3_Setup_3.6.1.exe,在安装的过程中啊,出现了各种问题,然后安装后了也出现打不开的 ...

  10. C11简洁之道:循环的改善

    1.  for循环的新用法 在C++98/03中,通过for循环对一个容器进行遍历,一般有两种方法,常规的for循环,或者使用<algorithm>中的for_each方法. for循环遍 ...