极简 DP,艺术暴力——面试题 17.23. 最大黑方阵
2024-02-04 19:37:11
好,让我们来看这道题,虽然说是一道动态规划的题目,但我们完全可以暴力解,这道题的做法有很多种,有 DP
也有 DFS
,但是我只想讲一种,那就是 DP
。
def maximalRectangle(matrix):
if not matrix:
return 0
m, n = len(matrix), len(matrix[0])
heights = [0] * n
maxArea = 0
for i in range(m):
for j in range(n):
if matrix[i][j] == '0':
heights[j] = 0
else:
heights[j] += 1
maxArea = max(maxArea, largestRectangleArea(heights))
return maxArea
def largestRectangleArea(heights):
heights.append(0)
stack = []
maxArea = 0
for i, height in enumerate(heights):
while stack and height < heights[stack[-1]]:
h = heights[stack.pop()]
w = i if not stack else i - stack[-1] - 1
maxArea = max(maxArea, h * w)
stack.append(i)
return maxArea
好,我们一个一个来看,首先这个矩阵,是一个 m 行 n 列的二维数组,而我们的目标是找到这个二维数组中,最大的全 1 子矩阵。
m, n = len(matrix), len(matrix[0])
接着,我们定义了一个列表 heights
,这个列表用来存储每一列的高度,高度定义为,从当前位置一直到最下面的全 1 的数量,那么为什么我们用高度来做文章呢?因为我们发现,这个问题可以转化为求最大矩形面积的问题。
heights = [0] * n
接下来,我们就开始遍历这个矩阵了,我们先遍历每一行,再遍历每一列,如果当前位置是 0,那么这个位置的高度就是 0,否则,我们就在原来的高度上加 1。
for i in range(m):
for j in range(n):
if matrix[i][j] == '0':
heights[j] = 0
else:
heights[j] += 1
遍历完一行后,我们就可以用 largestRectangleArea
函数来求出这一行的最大矩形面积,然后将这个面积和 maxArea
比较,取最大的。
maxArea = max(maxArea, largestRectangleArea(heights))
最后,我们遍历完所有的行后,maxArea
就是最大的矩形面积了。
return maxArea
接着我们再来看 largestRectangleArea
函数,这个函数用来求一个列表中,最大矩形面积。
def largestRectangleArea(heights):
我们先在列表的末尾加一个 0,这个 0 是为了方便我们处理边界情况。
heights.append(0)
然后,我们定义一个栈 stack
,这个栈用来存储当前位置之前的柱子的高度。
stack = []
我们再定义一个变量 maxArea
,这个变量用来存储最大的矩形面积。
maxArea = 0
接着,我们开始遍历这个列表,对于每一个柱子,我们先判断栈是否为空,如果栈不为空,并且当前柱子的高度小于栈顶柱子的高度,那么我们就需要计算栈顶柱子的矩形面积,然后将栈顶柱子出栈。
for i, height in enumerate(heights):
while stack and height < heights[stack[-1]]:
h = heights[stack.pop()]
w = i if not stack else i - stack[-1] - 1
maxArea = max(maxArea, h * w)
计算矩形面积的时候,我们用当前柱子的高度乘以栈顶柱子到当前柱子的宽度,宽度是 i
减去栈顶柱子的索引减去 1。
w = i if not stack else i - stack[-1] - 1
计算完矩形面积后,我们将当前柱子的高度压入栈中。
stack.append(i)
遍历完所有的柱子后,我们就可以返回 maxArea
了。
return maxArea