解法一:中等暴力
提前预存好每个竖的连续区间是否全为1,并利用此信息,可使暴力复杂度达到O(N
2
^2
2M
2
^2
2),代码如下:
import numpy as np
class Solution:
def maximalRectangle(self, matrix: List[List[str]]) -> int:
if matrix == []: return 0
rows, cols = len(matrix), len(matrix[0])
ret = 0
one = np.zeros((cols, rows, rows), dtype=np.int32)
# init
for j in range(cols):
for i in range(rows):
for p in range(i, rows):
if matrix[p][j] == '1':
one[j][i][p] = 1
else: break
# 搜索
for i in range(rows):
for j in range(cols):
if matrix[i][j] == '0': continue
for p in range(i, rows):
if matrix[p][j] == '0': break
for q in range(j, cols):
if one[q][i][p]:
if (q-j+1)*(p-i+1) > ret:
ret = (q-j+1)*(p-i+1)
else: break
return ret
解法二:再优化暴力
这次咱们存好向右的最大长度,就不用一个一个遍历了。可让复杂度变为O(M
2
^2
2N)。其中,计算最长连续1个数时,可以用dp的思想实现快速计算。和马拉车算法有些类似,都看最长的是不是包含了,不过这个简单很多。再程序的第二部分,我们的做法是遍历所有柱子并记录每个柱子出发的最小值,比较暴力。到这一步,其实已经和84题类似了。
class Solution:
def maximalRectangle(self, matrix: List[List[str]]) -> int:
if len(matrix) == 0 or len(matrix[0]) == 0: return 0
ret = 0
rows, cols = len(matrix), len(matrix[0])
continue_ones = [[0 for _ in range(cols)] for _ in range(rows)]
# 构建
for i in range(rows):
for j in range(cols):
if i > 0 and matrix[i-1][j] == '1':
continue_ones[i][j] = continue_ones[i-1][j]-1
continue
for p in range(i, rows):
if matrix[p][j] == '1':
continue_ones[i][j] += 1
else: break
# 搜索
for i in range(rows):
for j in range(cols):
if matrix[i][j] == '0': continue
mi = rows
for p in range(j, cols):
if continue_ones[i][p] == 0:
break
if continue_ones[i][p] < mi:
mi = continue_ones[i][p]
if mi*(p-j+1) > ret:
ret = mi*(p-j+1)
return int(ret)
解法三:单调栈
利用84题单调栈的思想求中心扩散长度,可以在O(MN)复杂度内计算出结果。其中,dp数组由于可以用dp生成,可以用O(N)的空间来存储。这样我们就可以得到一个O(MN)的算法。
class Solution:
def maximalRectangle(self, matrix: List[List[str]]) -> int:
if len(matrix) == 0 or len(matrix[0]) == 0: return 0
ret = 0
rows, cols = len(matrix), len(matrix[0])
dp = [0 for _ in range(cols+2)] # 表示在任意一行,该位置连续向下的1的个数
# 构建
for i in range(rows-1, -1, -1):
for j in range(cols):
if matrix[i][j] == '0': dp[j+1] = 0
else: dp[j+1] += 1
# 搜索
stack = []
for j, num in enumerate(dp):
while stack and num < dp[stack[-1]]:
val = (j-stack[-2]-1)*dp[stack[-1]]
if val > ret: ret = val
stack.pop()
stack.append(j)
return ret
此时代码已经很简短了,而且搜索算法用的是84题最快的单调栈解法,代码干净又强大。