返回

极简 DP,艺术暴力——面试题 17.23. 最大黑方阵

前端

好,让我们来看这道题,虽然说是一道动态规划的题目,但我们完全可以暴力解,这道题的做法有很多种,有 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