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
解法
其实n^3的解法也过了……
参考:https://www.cnblogs.com/lupx/archive/2015/10/20/leetcode-85.html
解法一:同84
height[i]可以看成是前i行的每一列的1堆叠成一个直方图,每一列看成一个bar,那么height[i][j]就是第j个bar的高度
需要注意的是,每个bar有可能被0中断,这时候高度要重新算
class Solution(object):
def maximalRectangle(self, matrix):
"""
:type matrix: List[List[str]]
:rtype: int
"""
m = len(matrix)
if m==0:
return 0
n = len(matrix[0])
if n==0:
return 0
ans = 0
for i in xrange(m):
matrix[i] = map(lambda x:ord(x)-ord('0'), matrix[i])
heights = [0]*n
ans = 0
for i in xrange(m):
stack = []
for j in xrange(n):
heights[j] = (heights[j]+matrix[i][j]) if matrix[i][j] else 0
while len(stack) and heights[stack[-1]]>heights[j]:
k = stack.pop()
b = len(stack) and stack[-1]+1 or 0
ans = max(ans, heights[k]*(j-b))
stack.append(j)
while len(stack):
k = stack.pop()
b = len(stack) and stack[-1]+1 or 0
ans = max(ans, heights[k]*(n-b))
return ans
解法二:DP
简而言之是上一个版本的优化,上一个版本,每更新一行,stack都清空重新算一下
但是实际上,增加一行之后的直方图的宽度和上次次计算出来的宽度之间是有联系的
我们假设遍历了i行,而heights[j]和width[j]分别是第j个bar的高度,以及以第j个bar的高度为高的矩形的最大宽度
我们想想width[j]是怎么来的,它代表的是一个区间[s,t)
长度,其中在这个区间内的bar的高度都不低于heights[j]
当我们增加一行时,会出现以下的情况:
- martix[i+1][j]为0:这时候heights[j]突然降为0,那么理论上说
[s,t)
将会扩大到[0,n)
,但是这种情况下面积一定是0 - martix[i+1][j]为1:那么heights[j]会加1,第i+1行中:
- 如果列在区间
[s,t)
里的元素都是1,那么这个区间不会变【在区间外的就算加了1也挤不进来】 - 如果存在
k
∈
[
s
,
t
)
k\in[s,t)
k∈[s,t)是0,那么不幸,
heights[k]
降为0,一定不会在[s,t)
里了,所以我们可以知道新的[s,t)
要怎么来了:
新的s’是[s,j]
里 j最左边的1的位置(就是说令[s’,j]都是1的最小s’),而新的t’是[j+1,t]
里 j右边第一个0的位置注意,新的区间一定是老区间的子集,因为【在区间外的就算加了1也挤不进来】
- 如果列在区间
所以DP是指用DP来寻找s和t
算法如下:
left[j]
代表每个j对应的s,right[j]
代表每个j对应的t
L
和R
分别对应遍历到j时,j左边第一个0和右边第一个0的位置
- 如果
matrix[i+1][j]==0
:
left[j]=0
,right[j]=n
L=j
——从左向右遍历时
R=j
——从右向左遍历时 - 如果
matrix[i+1][j]==1
,显然:
left[j]=max(L+1,left[j])
right[j]=min(R,right[j])
代码如下:
class Solution(object):
def maximalRectangle(self, matrix):
"""
:type matrix: List[List[str]]
:rtype: int
"""
m = len(matrix)
if m==0:
return 0
n = len(matrix[0])
if n==0:
return 0
h = [0]*n
ans = 0
l = [-1]*n
r = [n]*n
for i in xrange(m):
R = n
for j in xrange(n-1,-1,-1):
if matrix[i][j]=='0':
r[j] = n
R = j
else:
r[j] = min(r[j],R)
L = -1
for j in xrange(n):
if matrix[i][j]=='1':
h[j] += 1
l[j] = max(l[j],L+1)
else:
h[j] = 0
l[j] = 0
L = j
ans = max(ans, h[j]*(r[j]-l[j]))
return ans
不幸并没有比stack快很多……= =