题:https://leetcode.com/problems/maximal-rectangle/description/
#题目
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
解法
DP思想,对于每个 i,j 求它的 左右边界和累加的高度然后算法矩形的面积,由于高度为可以累加的,左右边界是继承的,即,上个row的i,j 的边界和现在i,j的边界关系是上个row的边界一定包含当前row边界。
通过左右各次扫描能得出相应的边界。
可以和 [LeetCode] 79. Word Search 对比下
故从上个row中提取最好,可能成为当前row最好的,这就是题目中的状态转移。
https://leetcode.com/problems/maximal-rectangle/discuss/29054/Share-my-DP-solution
The DP solution proceeds row by row, starting from the first row. Let the maximal rectangle area at row i and column j be computed by [right(i,j) - left(i,j)]*height(i,j).
All the 3 variables left, right, and height can be determined by the information from previous row, and also information from the current row. So it can be regarded as a DP solution. The transition equations are:
left(i,j) = max(left(i-1,j), cur_left), cur_left can be determined from the current row
right(i,j) = min(right(i-1,j), cur_right), cur_right can be determined from the current row
height(i,j) = height(i-1,j) + 1, if matrix[i][j]==‘1’;
height(i,j) = 0, if matrix[i][j]==‘0’
The code is as below. The loops can be combined for speed but I separate them for more clarity of the algorithm.
code
class Solution:
def maximalRectangle(self, matrix):
"""
:type matrix: List[List[str]]
:rtype: int
"""
m = len(matrix)
if m == 0:
return 0
n = len(matrix[0])
bleft = {}
bright ={}
heights = {}
for i in range(n):
bleft[i] = -1
bright[i] = n
heights[i] = 0
maxm = 0
for i in range(m):
cur_left = -1
cur_right = n
for j in range(n):
if matrix[i][j] == "1":
bleft[j] = max(bleft[j],cur_left)
heights[j] += 1
else:
bleft[j] = -1
cur_left = j
heights[j] = 0
for j in range(n-1,0-1,-1):
if matrix[i][j] == "1":
bright[j] = min(bright[j],cur_right)
else:
bright[j] = n
cur_right = j
for j in range(n):
maxm = max(maxm,heights[j]*(bright[j]-bleft[j]-1))
return maxm
二刷
对于 矩阵的 每个元素 i,j,可以得到获得一种矩阵,这个矩阵是 第 j 列 ,从 第 i 行 向上延申能 获取的 最高高度的 矩阵。
换句话说,对 每个元素 i,j,向上看 可以 看作 是一个 直方图。
可获得 以每列为 矩阵最高 位置的 矩阵大小。
下面的DP 也就是求这个问题。
DP 主要是 针对 左右边界 的 获取。
状态:
int[i][j] heights : 在i,j 位置 向上 直方图的位置。
int[i][j] leftBound: i,j 位置 的左边界。
int[i][j] rightBound: i,j 位置 的右边界。
初始状态:
int[i][j] heights = 0
int[i][j] leftBound =0
int[i][j] rightBound = COL
状态转移:
高度:
if(matrix[i][j]=='1'){
height[i][j] = height[i-1][j] + 1;
}else{
height[i][j] = 0;
}
左边界:
if(matrix[i][j]=='1'){
leftBound[i][j] = Math.max(leftBound[i-1][j],curLeftBound);
}else{
curLeftBound = j + 1;
leftBound[i][j] = 0;
}
右边界:
if(matrix[i][j]=='1'){
rightBound[j] = Math.min(rightBound[j],curRightBound);
}else{
curRightBound = j;
rightBound[j]=COL;
}
由于是 dp[i] 只 依靠 dp[i-1] 所以可以优化。
class Solution {
public int maximalRectangle(char[][] matrix) {
int ROW = matrix.length;
if(ROW == 0)
return 0;
int COL = matrix[0].length;
int[] height = new int[COL];
int[] leftBound = new int[COL];
int[] rightBound = new int[COL];
Arrays.fill(rightBound,COL);
int res = 0;
for(int i =0 ; i < ROW ; i++){
int curLeftBound = 0;
int curRightBound = COL;
for(int j = COL-1;j>=0 ; j--){
if(matrix[i][j]=='1'){
rightBound[j] = Math.min(rightBound[j],curRightBound);
}else{
curRightBound = j;
rightBound[j]=COL;
}
}
for(int j = 0 ; j <COL ; j++){
if(matrix[i][j]=='1'){
height[j]++;
leftBound[j] = Math.max(leftBound[j],curLeftBound);
res = Math.max(res,(rightBound[j] - leftBound[j])*height[j]);
}else{
height[j] = 0;
curLeftBound = j + 1;
leftBound[j] =0;
}
}
}
return res;
}
}