LeetCode 221. Maximal Square

本文介绍了一种寻找二维矩阵中只包含1的最大正方形及其面积的算法,通过动态规划的方法,实现了时间和空间效率的优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given a 2D binary matrix filled with 0’s and 1’s, find the largest square containing only 1’s and return its area.

For example, given the following matrix:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 4.

题意:给出一个由01填充的二维矩阵,找出只包含1的最大的正方形,并返回它的面积。

举一个栗子,现在我们要找下面这个矩阵在matrix[2][3]matrix[2][4]的面积:
1 0 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1

我们发现:划线的点处的最大面积为红、黄、绿三个正方形最小边+1的平方
这里写图片描述
下面我们看代码如何实现,代码中我会说明思路并举一个样例栗子:

class Solution {
public:
    /*
    假设dp[i][j]代表i行j列square的最大边长,我们发现:
    (1) dp[0][i] = matrix[0][i] (0 <= i < matrix[0].size)
        dp[j][0] = matrix[j][0] (0 <= j < matrix.size)
    (2) if matrix[i][j] != 0 :
       dp[i][j] = minNum(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;

    比如:

    1) matrix:          2) matrix:          3) matrix:          5) matrix:          
    1 0 1 0 0           [1 0] 1 0 0         1 [0 1] 0 0         1 0 1 [0 0]
    1 0 1 1 1           [1 0] 1 1 1         1 [0 1] 1 1         1 0 1 [1 1]
    1 1 1 1 1           1 1 1 1 1           1 1 1 1 1           1 1 1 1 1
    1 0 0 1 0           1 0 0 1 0           1 0 0 1 0     ...   1 0 0 1 0     ...

    1) dp[][]           2) dp[1][1]         3) dp[1][2]         5) dp[1][4]
    1 0 1 0 1           1 0 1 0 1           1 0 1 0 1           1 0 1 0 1
    1 * * * *           1 0 * * *           1 0 1 * *           1 0 1 1 1    
    1 * * * *           1 * * * *           1 * * * *           1 * * * * 
    1 * * * *           1 * * * *           1 * * * *     ...   1 * * * *     ...

    7) dp[2][1]         8) dp[2][2]         9) dp[2][3]         10) dp[2][4]
    1 0 1 0 1           1 0 1 0 1           1 0 1 0 1           1 0 1 0 1
    1 0 1 1 1           1 0 1 1 1           1 0 1 * *           1 0 1 1 1    
    1 1 * * *           1 1 1 2 2           1 1 1 2 2           1 1 1 2 2 
    1 * * * *           1 * * * *           1 * * * *     ...   1 * * * *     ...    

    */
    int maximalSquare(vector<vector<char>>& matrix) {
        if(matrix.empty()) return 0;

        int rows = matrix.size(), cols = matrix[0].size();
        int res = matrix[0][0] - '0';
        vector<vector<int> > dp(rows, vector<int>(cols, 0)); // 每个点的最大边长

        for(int i = 0; i < cols; ++i){  // 初始化第一行
            dp[0][i] = matrix[0][i] - '0';
            res = max(dp[0][i], res);   // 记录最大的边长
        }

        for(int i = 0; i < rows; ++i){  // 初始化第一列
            dp[i][0] = matrix[i][0] - '0';
            res = max(dp[i][0], res);   // 记录最大的边长
        }

        for(int i = 1; i < rows; ++i)
            for(int j = 1; j < cols; ++j)
                if(matrix[i][j] != '0'){
                    // 取决于三个正方形中最小正方形的边长 + 1
                    dp[i][j] = minNum(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
                    res = max(dp[i][j] , res);  // 记录最大的边长
                }

        return res * res;   // 返回边长的平方
    }

private:
    // 返回三个数中最小的数
    int minNum(const int &a, const int &b, const int& c){
        return a < b? (a < c ? a : c) : (b < c ? b : c);
    }
};

分析时间复杂度和空间复杂度:
Time Complexity:O(n*m) (m、n 分別代表行列数)
Space Complexity:O(n*m)

优化 Space Complexity:
我们发现,其实每次我们计算dp[i][j]都只依赖于dp[i - 1][j]dp[i][j - 1]、dp[i - 1][j - 1],所以对于dp[][],我们实际上只需要维持一行就可以了。不清楚的可以看上面代码举的栗子,计算第2行的dp[2][]时,我们只用到了第一行的dp[1][]。(当然也可以维持一列,其实还有一种方法不需要额外空间,但是需要修改matrix的值)

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if(matrix.empty()) return 0;

        int rows = matrix.size(), cols = matrix[0].size();
        int res = 0; // 最大边长
        vector<int> dp(cols, 0);

        for(int i = 0; i < cols; ++i){
            dp[i] = matrix[0][i] - '0';
            res = max(dp[i], res);  // 第0行是否存在最大边长
        }

        for(int i = 1; i < rows; ++i){
            int leftUp = dp[0];
            dp[0] = matrix[i][0] - '0';
            res = max(dp[0], res);    // 第0列是否存在最大边长
            for(int j = 1; j < cols; ++j){
                int temp = dp[j];   // 相当于记录dp[i - 1][j - 1]
                if(matrix[i][j] != '0'){
                    dp[j] = minNum(dp[j - 1]/*dp[i][j - 1]*/, dp[j] /*d[i - 1][j]*/, leftUp/*dp[i - 1][j - 1]*/) + 1;
                    res = max(dp[j], res);
                }
                else
                    dp[j] = 0; // 因为漏了matrix[i][j] == 0的时候,dp[j] = 0, 调了好久
                leftUp = temp;   // dp[i - 1][j - 1]
            }
        }
        return res * res;// 返回边长的平方
    }
private:
    // 返回三个数中最小的数
    int minNum(const int &a, const int &b, const int& c){
        return a < b? (a < c ? a : c) : (b < c ? b : c);
    }
};

到这里已经把Space Complexity控制在了O(n)或者O(m)

### 如何在 VSCode 中安装和配置 LeetCode 插件以及 Node.js 运行环境 #### 安装 LeetCode 插件 在 VSCode 的扩展市场中搜索 `leetcode`,找到官方提供的插件并点击 **Install** 按钮进行安装[^1]。如果已经安装过该插件,则无需重复操作。 #### 下载安装 Node.js 由于 LeetCode 插件依赖于 Node.js 环境,因此需要下载并安装 Node.js。访问官方网站 https://nodejs.org/en/ 并选择适合当前系统的版本(推荐使用 LTS 版本)。按照向导完成安装流程后,需确认 Node.js 是否成功安装到系统环境中[^2]。 可以通过命令行运行以下代码来验证: ```bash node -v npm -v ``` 上述命令应返回对应的 Node.js 和 npm 的版本号。如果没有正常返回版本信息,则可能未正确配置环境变量。 #### 解决环境路径问题 即使完成了 Node.js 的安装,仍可能出现类似 “LeetCode extension needs Node.js installed in environment path” 或者 “command ‘leetcode.toggleLeetCodeCn’ not found” 的错误提示[^3]。这通常是因为 VSCode 未能识别全局的 Node.js 路径或者本地安装的 nvm 默认版本未被正确加载[^4]。 解决方法如下: 1. 手动指定 Node.js 可执行文件的位置 在 VSCode 设置界面中输入关键词 `leetcode`,定位至选项 **Node Path**,将其值设为实际的 Node.js 安装目录下的 `node.exe` 文件位置。例如:`C:\Program Files\nodejs\node.exe`。 2. 使用 NVM 用户管理工具调整默认版本 如果通过 nvm 工具切换了不同的 Node.js 版本,请确保设置了默认使用的版本号。可通过以下指令实现: ```bash nvm alias default <version> ``` 重新启动 VSCode 后测试功能键是否恢复正常工作状态。 --- #### 配置常用刷题语言 最后一步是在 VSCode 设置面板中的 LeetCode 插件部分定义个人习惯采用的主要编程语言作为默认提交方式之一。这样可以减少频繁修改编码风格的时间成本。 --- ### 总结 综上所述,要在 VSCode 上顺利启用 LeetCode 插件及其关联服务,除了基本插件本身外还需额外准备支持性的后台框架——即 Node.js 应用程序引擎;同时针对特定场景下产生的兼容性障碍采取针对性措施加以修正即可达成目标[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值