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
Solution
Solution 1
2260 ms AC,速度比较慢。
将二维问题转化为一维求最长连续子序列的问题。对于第 i 行和第 j 行,求出 i 行到 j 行之间每一列的和,如果这个和等于 (j-i+1),(说明这一列全为 1,可以成为矩阵的一个列)将这一列标记为1,否则将这一列标记为0。然后第 i 行到第 j 列其实形成了一个只包含 0 和 1 的一维数组。
在计算两行之间的列的和的时候,用动态规划算法提高速度。用一个数组 sumarray 记录某位置及该列以上所有元素的和。sumarray[i][j] = sum of matrix[0][j], matrix[1][j] … matrix[i][j]。然后求两行直接的列和的时候直接用 sumarray 做差即可。
class Solution:
'''
给一个包含0和1的列表,求最长连续子序列
'''
def findMaxSequence(self, l: 'List[int]') -> 'int':
length= len(l)
max_length = 0
if length == 0:
return 0
dp = [0 for i in range(length)]
if l[0] == 1:
dp[0] = 1
for i in range(1, length):
if l[i] == 1:
if l[i-1] == 0:
dp[i] = 1
else:
dp[i] = dp[i-1] + 1
else:
dp[i] = 0
for i in range(length):
max_length = max(max_length, dp[i])
return max_length
def maximalRectangle(self, matrix: 'List[List[str]]') -> 'int':
rows = len(matrix)
if rows > 0:
cols = len(matrix[0])
max_area = 0
if rows==0 or cols==0:
return 0
# transfer it to an 'int' array
for i in range(rows):
for j in range(cols):
matrix[i][j] = int(matrix[i][j])
# sumarray[i][j]: sum of matrix[0][j], matrix[1][j] ... matrix[i][j]
sumarray = matrix.copy()
for i in range(1, rows):
for j in range(cols):
sumarray[i][j] = sumarray[i-1][j] + sumarray[i][j]
for i in range(rows):
for j in range(i, rows):
if (j-i+1)*cols < max_area:
continue
tmparray = []
for k in range(cols):
if i == 0:
delta = sumarray[j][k]
else:
delta = sumarray[j][k] - sumarray[i-1][k]
if delta == (j-i+1):
tmparray.append(1)
else:
tmparray.append(0)
# pruning
if sum(tmparray)*(j-i+1) < max_area:
continue
max_sequence = self.findMaxSequence(tmparray)
max_area = max(max_area, max_sequence * (j-i+1))
return max_area
Solution 2
92 ms AC.
联系 LeetCode 84. Largest Rectangle in Histogram,将二维矩阵问题转化为直方图中最大矩阵面积的问题。逐行遍历,遍历到第 row 行时,只看第 row 行及其以上的部分。heights[j] 表示 matrix[i][j] 这个元素及其以上的连续的 ‘1’ 的个数。所以当前行计算出的 heights 数组其实可以代表一个直方图,然后用 84 题中的算法(这里提供一个笔者的解题博客)计算直方图中最大矩阵面积。遍历完所有行之后,得到整个矩阵的最大长方形面积。
matrix:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
heights:
1 0 1 0 0
2 0 2 1 1
3 1 3 2 2
4 0 0 3 0
然后在第三行 3 1 3 2 2
时,得到直方图中最大矩阵面积是6,也是全局最优解。
class Solution:
'''
calculate the max area in the histogram
'''
def largestRectangInHistogram(self, row):
heights = [0] + row + [0]
stack = []
max_area = 0
for i in range(len(heights)):
if len(stack) == 0:
stack.append(i)
else:
while len(stack)>0 and heights[stack[-1]] > heights[i]:
top = stack.pop()
max_area = max(max_area, heights[top] * (i-stack[-1]-1))
stack.append(i)
return max_area
def maximalRectangle(self, matrix: 'List[List[str]]') -> 'int':
rows = len(matrix)
max_area = 0
if rows > 0:
cols = len(matrix[0])
else:
return 0
# heights[i]: Number of consecutive '1' above matrix[i][j] (including matrix[i][j])
heights = [0 for i in range(cols)]
for i in range(rows):
for j in range(cols):
if matrix[i][j] == '1':
heights[j] = heights[j] + 1
else:
heights[j] = 0
max_rectangle_this_row = self.largestRectangInHistogram(heights)
max_area = max(max_area, max_rectangle_this_row)
return max_area