当前位置: 面试刷题>> 最大子矩阵 (经典算法题500道)


题目描述

最大子矩阵 是一道经典的动态规划或线性代数结合扫描线的算法题。题目要求在给定的一个二维01矩阵中,找出只包含1的最大子矩阵,并返回该子矩阵的面积(即其中1的个数)。子矩阵可以是矩形或正方形,但不能是空集,且必须保持矩形的形状(即行和列都是连续的)。

示例

给定以下矩阵:

0 1 0 0 0
1 1 0 1 1
1 0 0 1 0
1 1 1 1 1
0 0 0 0 0

最大的全1子矩阵是:

1 1 1 1 1

其面积为5。

PHP 代码示例

function maximalRectangle($matrix) {
    if (empty($matrix)) return 0;
    
    $rows = count($matrix);
    $cols = count($matrix[0]);
    $heights = array_fill(0, $cols, 0); // 记录每一列连续1的高度
    $maxArea = 0;
    
    for ($i = 0; $i < $rows; $i++) {
        for ($j = 0; $j < $cols; $j++) {
            if ($matrix[$i][$j] == '1') {
                $heights[$j]++; // 如果当前位置是1,则当前列的高度加1
            } else {
                $heights[$j] = 0; // 如果当前位置是0,则重置当前列的高度为0
            }
        }
        
        // 对当前行形成的柱状图求最大矩形面积
        $maxArea = max($maxArea, largestRectangleArea($heights));
    }
    
    return $maxArea;
}

function largestRectangleArea($heights) {
    $stack = []; // 使用单调栈来找到每个柱子可以向左和向右扩展的最远位置
    $heights[] = 0; // 添加一个哨兵元素,方便处理栈中剩余元素
    $maxArea = 0;
    
    for ($i = 0; $i < count($heights); $i++) {
        while (!empty($stack) && $heights[$i] < $heights[end($stack)]) {
            $h = $heights[array_pop($stack)];
            $w = $stack ? $i - end($stack) - 1 : $i;
            $maxArea = max($maxArea, $h * $w);
        }
        $stack[] = $i;
    }
    
    return $maxArea;
}

// 示例使用
$matrix = [
    [0, 1, 0, 0, 0],
    [1, 1, 0, 1, 1],
    [1, 0, 0, 1, 0],
    [1, 1, 1, 1, 1],
    [0, 0, 0, 0, 0]
];

echo maximalRectangle($matrix); // 输出 5

Python 代码示例

Python 代码与 PHP 类似,但语法和库函数有所不同。

JavaScript 代码示例

JavaScript 版本的实现也会遵循相同的逻辑,但具体语法和库函数的使用会有所不同。

注意事项

  1. 时间复杂度:整个算法的时间复杂度主要由对每行更新高度和计算每行高度形成的柱状图的最大矩形面积两部分组成,大约为 O(m * n),其中 m 是行数,n 是列数。
  2. 空间复杂度:O(n),用于存储每列的高度。

码小课 网站中有更多关于算法和数据结构的精彩内容,可以帮助大家更深入地学习和理解这些概念。

推荐面试题