problem
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:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 4.
solution
这个问题可以使用二维dp来求解,x(i, j)表示以(i, j)为右下角的正方形的最大边长,y(i, j)表示(i, j)处向左最长的连续’1’的数目,z(i, j)表示向上最长的连续’1’的数目。这样递推方程为
x = d[(i-1, j-1)][0]
y = d[(i, j-1)][1]
z = d[(i-1, j)][2]
d[(i, j)] = (1 + min(x, y, z), y+1, z+1)
代码如下(超过10%):
class Solution(object):
def maximalSquare(self, matrix):
"""
:type matrix: List[List[str]]
:rtype: int
"""
m = len(matrix)
if not m:
return 0
n = len(matrix[0])
ans = 0
d = {}
for i in range(m):
if matrix[i][0] == u'1':
d[(i, 0)] = (1, 1, 1)
ans = 1
else:
d[(i, 0)] = (0, 0, 0)
for i in range(n):
if matrix[0][i] == u'1':
d[(0, i)] = (1, 1, 1)
ans = 1
else:
d[(0, i)] = (0, 0, 0)
for i in range(1, m):
for j in range(1, n):
if matrix[i][j] == u'0':
d[(i, j)] = (0,0,0)
else:
x = d[(i-1, j-1)][0]
y = d[(i, j-1)][1]
z = d[(i-1, j)][2]
d[(i, j)] = (1 + min(x, y, z), y+1, z+1)
ans = max(ans, 1 + min(x, y, z))
return ans**2
优化:
上面的递推公式用了向右和向左的最长距离,其实只用以(i, j)为右下角的正方形的最大边长就可以完成递推,dp(i, j)=min(dp(i−1, j), dp(i−1, j−1),
时间和空间复杂度为O(mn)
class Solution(object):
def maximalSquare(self, matrix):
"""
:type matrix: List[List[str]]
:rtype: int
"""
m = len(matrix)
if not m:
return 0
n = len(matrix[0])
ans = 0
d = {}
for i in range(m):
if matrix[i][0] == u'1':
d[(i, 0)] = 1
ans = 1
else:
d[(i, 0)] = 0
for i in range(n):
if matrix[0][i] == u'1':
d[(0, i)] = 1
ans = 1
else:
d[(0, i)] = 0
for i in range(1, m):
for j in range(1, n):
if matrix[i][j] == u'0':
d[(i, j)] = 0
else:
x = d[(i-1, j-1)]
y = d[(i, j-1)]
z = d[(i-1, j)]
d[(i, j)] = 1 + min(x, y, z)
ans = max(ans, 1 + min(x, y, z))
# print(d)
return ans**2
优化的dp算法
可以观察到每行只用到上一行的数据,因此我们只需要存储一行子问题的解,这样就把问题的空间复杂度降为O(n)
总结
动态规划两个关键点就是子问题形式和递推方程,这个问题主要考察递推方程的形式。