【1.6】动态规划-解最大正方形

一、题目

        在一个由'0'和'1'组成的二维矩阵内,找到 只包含'1'的最大正方形 ,并返回其面积。

输入
matrix =
[ [" 1 "," 0 "," 1 "," 0 "," 0 "] ,
[" 1 "," 0 "," 1 "," 1 "," 1 "] ,
[" 1 "," 1 "," 1 "," 1 "," 1 "] ,
[" 1 "," 0 "," 0 "," 1 "," 0 "] ]
输出 4

输入 m a tri x = [ [" 0 "," 1 "] , [" 1 "," 0 "] ]
输出 1
示例 3
输入 m a tri x = [ [" 0 "] ]
输出 0
提示:
m == ma tri x . l ength
n == ma tri x [i]. l ength
1 <= m, n <= 300
ma tri x [i][j] 为 '0' 或 '1'

二、求解思路

        题目要求我们找出由数字1构成的最大正方形。最直观的解决方案是采用暴力搜索方法。具体来说,如果某个位置的值为1,我们就将其视为正方形的左上角,然后向右和向下搜索,尝试找到最大的正方形,同时确保该正方形内的所有值均为1。

        尽管这种方法易于理解,但编写代码较为复杂,且时间效率较低。因此,我们转向另一种更为高效的解决方案——动态规划。

        我们定义一个二维数组dp[m][n],其中dp[i][j]表示以矩阵中坐标(i, j)为右下角的最大正方形的边长。为了求解dp[i][j],我们需要检查矩阵中matrix[i][j]的值。

        如果matrix[i][j]为0,则无法构成正方形,因此dp[i][j] = 0。
        如果matrix[i][j]为1,表明至少可以构成一个边长为1的正方形。为了找到更大的正方形,我们还需要检查其左上角的值dp[i-1][j-1]。如果dp[i-1][j-1]为0,那么以坐标(i, j)为右下角的最大正方形边长就是1,如下图所示:

        如果左上角的值 dp[i -1][j -1] 不是0,也就是说他也可以构成正方形,那么以坐标 (i , j) 为
右下角有可能可以构成一个更大的正方形。为啥说是有可能,因为如果我们要确定他能不
能构成一个更大的正方形,还要往他的上边和左边找 ,看看下面的图

        有可能是下面这种情况,就是左边或者上边的某一个高度小于 dp[i -1][j -1] 的值,要想构
成最大的正方形我们只能取最小的。

        也有可能是下面这种,就是左边和上边的高度都不小于 dp[i -1][j -1] 的值。

        所以我们可以得出结论,如果 (i , j) 是1,那么以他为右下角的最大正方形边长是
{dp[i -1][j -1],上边的高度,左边的高度}这3个中最小的+1。 这 里 有 个 问 题 就 是 , 如 果 (i , j) 是 1 , 我 们 有 必 要 往 他 的 上 边 和 左 边 查 找 吗 , 很 明 显 没 必要,上边可以用 dp[i -1][j] 来代表,左边可以用dp[i][j -1]来代表。注意这里 dp[i -1] [j] 并不是上边为1的高度,dp[i -1][j] 只会小,不会大,可以想一下为什么可以代表。
所以我们可以找出递推公式 :
如果坐标(i,j)为0,
则dp[i][j]=0;
如果坐标(i,j)为1,
则dp[i][j]=min(dp[i -1][j],dp[i][j -1],dp[i -1][j -1])+1;

三、代码实现

c++代码实现如下:
 

#include <iostream>
#include <vector>
#include <algorithm>

// 声明 maximalSquare 函数
int maximalSquare(std::vector<std::vector<char>>& matrix);

int main() {
    // 定义一个二维字符数组(矩阵)
    std::vector<std::vector<char>> matrix = {
        {'1', '0', '1', '0', '0'},
        {'1', '0', '1', '1', '1'},
        {'1', '1', '1', '1', '1'},
        {'1', '0', '0', '1', '0'}
    };

    // 调用 maximalSquare 函数并获取结果
    int result = maximalSquare(matrix);

    // 输出结果
    std::cout << "The area of the largest square containing all '1's is: " << result << std::endl;

    return 0;
}

// 定义 maximalSquare 函数
int maximalSquare(std::vector<std::vector<char>>& matrix) {
    // 二维矩阵的宽和高
    int height = matrix.size();
    int width = matrix[0].size();
    std::vector<std::vector<int>> dp(height + 1, std::vector<int>(width + 1, 0));
    int maxSide = 0; // 最大正方形的宽

    for (int i = 1; i <= height; i++) {
        for (int j = 1; j <= width; j++) {
            if (matrix[i - 1][j - 1] == '1') {
                // 递推公式
                dp[i][j] = std::min({dp[i - 1][j], dp[i - 1][j - 1], dp[i][j - 1]}) + 1;
                // 记录最大的边长
                maxSide = std::max(maxSide, dp[i][j]);
            }
        }
    }
    // 返回正方形的面积
    return maxSide * maxSide;
}

 

  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城狮7号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值