动态规划的“降维”艺术:二维矩阵中的建筑奇迹——最大矩形

哈喽,各位,我是前端小L。

我们的DP之旅,已经探索了序列、树、乃至各种抽象的匹配和计数问题。今天,我们重返二维矩阵这片熟悉的土地,但要挑战一个全新的、更具"几何感"的目标:在这片由01构成的土地上,圈出那块只包含1的、面积最大的矩形地块。

这道题是DP与数据结构(特别是单调栈)结合的典范。它将向我们展示,最高级的算法思想,往往不是硬碰硬地增加维度,而是巧妙地**"降维打击"**,将一个高维度的难题,分解成我们能够轻松解决的低维度问题。

力扣 85. 最大矩形

https://leetcode.cn/problems/maximal-rectangle/

题目分析: 在一个由 01 组成的二维矩阵中,找到只包含 1 的最大矩形的面积。

思路一:朴素DP的尝试与瓶颈

一个很自然的想法是,我们能否用 dp[i][j] 来记录一些信息,从而推导出答案? 我们可以定义 dp[i][j] 为:在以 (i, j)右下角 的矩形中,只包含1的最大面积。 但这很难!因为要确定面积,dp[i][j] 不仅需要知道自己的高度和宽度,还需要知道 dp[i-1][j], dp[i][j-1] 等多个状态的几何信息,状态转移会变得异常复杂。

一个稍微好一点的定义是:dp[i][j] 表示在第 i 行,以 (i, j) 结尾的连续 1 的个数(即宽度)。 dp[i][j] = (matrix[i][j] == '1') ? dp[i][j-1] + 1 : 0 有了这个"宽度"信息后,要计算以 (i, j) 为右下角的矩形的最大面积,我们还需要向上遍历 ki0,找出在这些行中,[k...i] 范围内宽度的最小值 ,然后乘以高度 (i-k+1)。 这个思路的时间复杂度是 O(m * n * m),依然不够理想。

思路二:"Aha!"时刻 ------ 从矩阵到直方图的降维打击

让我们换一个视角,逐行 地审视这个矩阵。 当我们处理到第 i 行时,我们不把它看作孤立的一行,而是把它看作一个**"地基"**。

我们可以定义一个 heights 数组,heights[j] 表示在第 i 行、第 j 列的位置,向上 能延伸的连续 1 的最大高度。

举个例子: matrix = [ ["1","0","1","0","0"], ["1","0","1","1","1"], <-- 我们现在处理到这一行 (i=1) ["1","1","1","1","1"], ["1","0","0","1","0"] ]

i = 1 时,我们来计算每个位置的"高度":

  • heights[0]: matrix[0][0]matrix[1][0] 都是 1,所以高度是 2

  • heights[1]: matrix[1][1]0,高度中断,所以是 0

  • heights[2]: matrix[0][2]matrix[1][2] 都是 1,所以高度是 2

  • heights[3]: matrix[0][3]0matrix[1][3]1,所以高度是 1

  • heights[4]: matrix[0][4]0matrix[1][4]1,所以高度是 1

在第 i=1 行,我们得到了一个高度数组:heights = [2, 0, 2, 1, 1]

现在,最关键的一步来了! 在以第 i 行为"地基"的所有可能矩形中,寻找面积最大的那个,这个问题,与在一个由 heights 数组构成的"直方图"中,寻找最大矩形面积的问题,是完全等价的!

这不就是我们另一道经典难题 LC 84. 柱状图中最大的矩形 吗?!

我们成功地,把一个二维(m*n) 矩阵问题,分解成了 m一维(1*n) 直方图问题!

最终算法:逐行构建直方图 + 单调栈

现在,我们的宏伟蓝图已经清晰了:

  1. 初始化 maxArea = 0

  2. 创建一个 heights 数组,长度为 n(矩阵的列数),初始为0。

  3. 逐行遍历 矩阵 (从 i = 0m-1): a. 更新 heights 数组 :遍历当前行 i 的每一列 j。 * 如果 matrix[i][j] == '1',那么 heights[j] 的高度就增加1。 * 如果 matrix[i][j] == '0',说明连续的 1 在此中断,heights[j] 的高度必须归零 。 b. 解决子问题 :对当前更新后的 heights 数组,调用"柱状图中最大的矩形"的解法(通常使用单调栈 ),计算出当前行的最大矩形面积 currentMax。 c. 更新全局最优解maxArea = max(maxArea, currentMax)

  4. 所有行遍历完毕后,maxArea 就是最终答案。

代码实现 (融合 LC 84 的解法)

复制代码
#include <stack>
class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if (matrix.empty() || matrix[0].empty()) {
            return 0;
        }
        int m = matrix.size();
        int n = matrix[0].size();
        
        vector<int> heights(n, 0);
        int maxArea = 0;

        for (int i = 0; i < m; ++i) {
            // 1. 更新 heights 数组
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == '1') {
                    heights[j] += 1;
                } else {
                    heights[j] = 0;
                }
            }
            // 2. 调用 LC 84 的解法
            maxArea = max(maxArea, largestRectangleInHistogram(heights));
        }
        return maxArea;
    }

private:
    // LeetCode 84: 柱状图中最大的矩形 (单调栈解法)
    int largestRectangleInHistogram(vector<int>& heights) {
        stack<int> s;
        heights.push_back(0); // 哨兵,确保所有柱子都能被弹出计算
        int maxArea = 0;
        
        for (int i = 0; i < heights.size(); ++i) {
            while (!s.empty() && heights[s.top()] >= heights[i]) {
                int h = heights[s.top()];
                s.pop();
                int w = s.empty() ? i : i - s.top() - 1;
                maxArea = max(maxArea, h * w);
            }
            s.push(i);
        }
        heights.pop_back(); // 恢复原状 (好习惯)
        return maxArea;
    }
};

总结:DP思维的更高境界

今天这道题,是动态规划思想的一次华丽"变身"。它深刻地告诉我们:

最高级的DP,有时并不是构建更复杂的DP状态,而是将原问题分解、转化为我们已知的、更简单的DP模型。

这种**"问题转化" "降维"**的能力,是衡量一个算法工程师水平高低的重要标志。它要求我们不仅要会"做题",更要在大脑中建立起一个"问题模型库",在面对新问题时,能够迅速地进行模式匹配。

从今天起,当你再遇到一个看似棘手的二维矩阵问题时,不妨问问自己:"我能不能把它切成一片片,变成我熟悉的一维问题来解决?"

咱们下期见~

相关推荐
小龙5 小时前
【理论知识】Q/K/V权重矩阵学习笔记
矩阵·大模型·transformer·多头注意力机制·理论基础
无限进步_5 小时前
【C语言】在矩阵中高效查找数字的算法解析
c语言·开发语言·数据结构·c++·其他·算法·矩阵
张晓~183399481211 天前
碰一碰发抖音源码技术搭建部署方案
线性代数·算法·microsoft·矩阵·html5
dxnb221 天前
Datawhale25年10月组队学习:math for AI+Task3线性代数(下)
人工智能·学习·线性代数
woshihonghonga1 天前
PyTorch矩阵乘法函数区别解析与矩阵高级索引说明——《动手学深度学习》3.6.3、3.6.4和3.6.5 (P79)
人工智能·pytorch·python·深度学习·jupyter·矩阵
CLubiy1 天前
【研究生随笔】Pytorch中的线性代数(微分)
人工智能·pytorch·深度学习·线性代数·梯度·微分
郝学胜-神的一滴1 天前
矩阵的奇异值分解(SVD)及其在计算机图形学中的应用
程序人生·线性代数·算法·矩阵·图形渲染
豆沙沙包?3 天前
2025年--Lc201- 378. 有序矩阵中第 K 小的元素(排序)--Java版
java·线性代数·矩阵
CLubiy3 天前
【研究生随笔】Pytorch中的线性代数
pytorch·python·深度学习·线性代数·机器学习