【LeetCode】动态规划—221. 最大正方形(附完整Python/C++代码)

news2024/9/30 11:45:01

动态规划—221. 最大正方形

  • 前言
  • 题目描述
  • 基本思路
    • 1. 问题定义:
    • 2. 理解问题和递推关系:
    • 3. 解决方法:
      • 3.1 动态规划方法
      • 3.2 空间优化的动态规划
    • 4. 进一步优化:
    • 5. 小总结:
  • 代码实现
    • Python3代码实现
    • Python 代码解释
    • C++代码实现
    • C++ 代码解释

前言

在二维矩阵中寻找最大正方形的问题是动态规划的一个经典应用。这个问题不仅考察我们对二维数组的操作,还需要我们理解如何通过递推公式优化解法。矩阵中的每个元素都可能成为一个正方形的一部分,而我们要做的就是利用之前的计算结果,在矩阵的每个位置处找到能够扩展出的最大正方形。

本文将介绍如何通过动态规划方法解决这一问题。我们会逐步分析递推关系,并通过 Python 和 C++ 代码示例展示具体的实现,并在最后总结代码的实现细节。

题目描述

在这里插入图片描述

基本思路

1. 问题定义:

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

2. 理解问题和递推关系:

  • 该问题的本质是求解在矩阵中可以组成最大正方形的边长,并最终返回其面积。
  • 假设 d p [ i ] [ j ] d p[i][j] dp[i][j] 表示以位置 ( i , j ) (i, j) (i,j) 为右下角的最大正方形的边长。为了构成一个更大的正方形,要求该位置的左边、上边和左上角位置的 d p d p dp 值都要有足够的边长。因此,状态转移方程为:

d p [ i ] [ j ] = min ⁡ ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j − 1 ] ) + 1 d p[i][j]=\min (d p[i-1][j], d p[i][j-1], d p[i-1][j-1])+1 dp[i][j]=min(dp[i1][j],dp[i][j1],dp[i1][j1])+1

其中, d p [ i − 1 ] [ j ] d p[i-1][j] dp[i1][j] 表示上边的正方形边长, d p [ i ] [ j − 1 ] d p[i][j-1] dp[i][j1] 表示左边的正方形边长, d p [ i − 1 ] [ j − 1 ) d p[i-1][j- 1) dp[i1][j1表示左上角的正方形边长。三者的最小值加上当前的 1 1 1 就可以组成一个新的正方形。

  • 边界条件:如果当前位置的值是 ’ 0 ′ 0^{\prime} 0 ,那么 d p [ i ] [ j ] = 0 d p[i][j]=0 dp[i][j]=0 ,因为无法形成任何正方形。

3. 解决方法:

3.1 动态规划方法

  1. 创建一个二维数组 d p , d p [ i ] [ j ] d p, d p[i][j] dp,dp[i][j] 表示以 m a t r i x [ i ] [ j ] matrix[i][j] matrix[i][j] 为右下角的最大正方形的边长。
  2. 初始化 d p d p dp 的第一行和第一列,直接等于矩阵的第一行和第一列的值,因为这些位置无法通过左上、上、左来扩展。
  3. 从第二行、第二列开始,依次计算 d p [ i ] [ j ] d p[i][j] dp[i][j] ,并记录最大正方形的边长。
  4. 结果为最大边长的平方,即最大正方形的面积。

3.2 空间优化的动态规划

  • 由于每次计算 d p [ i ] [ j ] dp[i][j] dp[i][j] 时只依赖于左边、上边和左上角的位置, 因此可以通过一维数组优化空间复杂度。
  • 在计算过程中,我们只需要保存当前行和前一行的数据,从而将空间复杂度优化为 O ( n ) O(n) O(n)

4. 进一步优化:

  • 空间优化:使用一维数组来代替二维 d p d p dp 数组,通过滚动数组的方式减少空间量杂度,从 O ( m ∗ n ) O(m * n) O(mn) 降低到 O ( n ) O(n) O(n)

5. 小总结:

  • 动态规划方法通过逐步扩展矩阵中的 ′ 1 ′ ' 1 ' 1,计算出可以形成的最大正方形。该方法在时间昜杂度和空间昜杂度上表现较为优采。
  • 通过优化空间复杂度,可以将存储空间减少到 O ( n ) O(n) O(n) ,适用于大规模数据处理。动态规划问题的核心在于找到合理的递推关系,并根据问题特点优化计算过程。

以上就是最大正方形问题的基本思路。

代码实现

Python3代码实现

class Solution:
    def maximalSquare(self, matrix: list[list[str]]) -> int:
        if not matrix or not matrix[0]:
            return 0
        
        rows, cols = len(matrix), len(matrix[0])
        dp = [[0] * cols for _ in range(rows)]
        max_side = 0
        
        for i in range(rows):
            for j in range(cols):
                if matrix[i][j] == '1':
                    if i == 0 or j == 0:  # 边界条件,第一行或第一列
                        dp[i][j] = 1
                    else:
                        dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
                    max_side = max(max_side, dp[i][j])
        
        # 最大面积
        return max_side * max_side

Python 代码解释

  • 初始化:首先初始化 d p dp dp 数组, d p [ i ] [ j ] dp[i][j] dp[i][j] 用于记录以 ( i , j ) (i, j) (i,j) 为右下角的最大正方形的边长。然后,遍历矩阵的每个元素。
  • 递推公式:当遇到矩阵元素为 1 时,计算 d p [ i ] [ j ] dp[i][j] dp[i][j] 的值。 d p [ i ] [ j ] dp[i][j] dp[i][j] 取决于左边、上边和左上角三个位置中最小的 d p dp dp 值,然后加 1 1 1
  • 边界条件:如果元素位于第一行或第一列,无法从上方或左方扩展正方形,因此直接将 d p [ i ] [ j ] dp[i][j] dp[i][j] 设为 1 1 1
  • 结果计算:每次计算时更新最大边长 max_side,最后返回最大边长的平方,即最大正方形的面积。

C++代码实现

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if (matrix.empty() || matrix[0].empty()) return 0;
        
        int rows = matrix.size();
        int cols = matrix[0].size();
        vector<vector<int>> dp(rows, vector<int>(cols, 0));
        int max_side = 0;
        
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                if (matrix[i][j] == '1') {
                    if (i == 0 || j == 0) {  // 边界条件,第一行或第一列
                        dp[i][j] = 1;
                    } else {
                        dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + 1;
                    }
                    max_side = max(max_side, dp[i][j]);
                }
            }
        }
        
        // 最大面积
        return max_side * max_side;
    }
};

C++ 代码解释

  • 初始化:首先创建 dp 数组,dp[i][j] 用于存储以 (i, j) 为右下角的最大正方形边长。初始化最大边长 max_side。
  • 动态规划递推:遍历矩阵中的每个位置。当 matrix[i][j] == '1' 时,通过递推公式计算 dp[i][j],更新 max_side。
  • 边界条件:对于第一行或第一列,直接将 dp[i][j] 设为1,因为无法通过左上、上方和左方扩展正方形。
  • 结果计算:最终返回最大边长的平方,即最大正方形的面积。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2179527.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql笔记10(高级部分--跟数据库管理有关)

文章目录 一、视图(view)1. 作用2. CRUD--跟表操作几乎相同① 创建② 显示视图③ 查看视图相关详细信息④ 删除视图⑤ 更新视图 3. 视图算法① 创建视图时指定视图算法② 后期navicat里修改视图算法③ 注 二、事务(transaction)1. 事务的提出2. 举例理解① commit -- 一起执行②…

CSS宽度和高度

CSS 尺寸属性指的就是元素的宽度和高度属性&#xff0c;虽然说非常简单&#xff0c;但却是必须掌握的技能。CSS 中提供了 width、height、max-width、min- width、max-height 和 min-height 等几个属性来设置元素的宽度和高度&#xff0c;这些元素使用起来非常简单&#xff0c;…

采购订单管理:如何驱动业务效率和增长

采购订单是一份具有法律约束力的文件&#xff0c;明确了买方在未来特定日期从供应商处购买商品或服务的意图。 该文件对于买卖双方均具有重要价值。对于买方而言&#xff0c;采购订单有助于其进行未来数月的财务规划&#xff0c;明确资金的支出时间点。对于供应商而言&#x…

如何快速建立自己的异地互联的远程视频监控系统,通过web浏览器可以直接查看公网上的监控视频(上)

目录 一、需求 二、方案 2.1、计划方案 2.2、实施准备 2.2.1所需配置的产品和服务 2.2.1.1云主机 &#xff08;1&#xff09;选择云平台 &#xff08;2&#xff09;配置云服务器 2.2.2.2视频监控平台软件 &#xff08;1&#xff09;视频监控平台软件 &#xff08;2&am…

袋鼠云数据资产平台:数据模型标准化建表重构升级

数据模型是什么&#xff1f;简单来说&#xff0c;数据模型是用来组织和管理数据的一种方式。它为构建高效且可靠的信息系统提供了基础&#xff0c;不仅决定了如何存储和管理数据&#xff0c;还直接影响系统的性能和可扩展性。 想要建立一个良好的数据模型&#xff0c;设计时需…

【从0开始搭建微服务并进行部署】SpringBoot+dubbo+zookeeper

文章目录 说明环境搭建创建项目父模块设置子模块 dubbo-api子模块 dubbo-provider子模块 dubbo-consumer测试项目 docker部署项目完整项目地址 说明 jdk1.8SpringBoot2.x低版本dubbo&#xff1a;请查看之前教程【微服务】SpringBootDubboZooKeeper 实战 关于本教程将采用jdk1…

springboot整合Freemarker动态生成JSON

什么是Freemarker 链接: Freemarker介绍和语法 FreeMarker 是一款模板引擎&#xff1a; 即一种基于模板和要改变的数据&#xff0c; 并用来生成输出文本(HTML网页&#xff0c;电子邮件&#xff0c;配置文件&#xff0c;源代码等)的通用工具。 它不是面向最终用户的&#xff0c…

node实现大文件切片上传的方法

切片上传定义 文件切片上传&#xff0c;也称为分片上传&#xff0c;是一种处理大文件上传的有效方法。该方法通过将大文件分割成多个较小的部分&#xff08;即切片或分片&#xff09;&#xff0c;然后分别上传这些切片到服务器&#xff0c;最后在服务器上将这些切片合并成原始文…

新手教学系列——用 VSCode 实现高效远程开发

随着软件开发环境日益复杂,远程开发已成为许多开发者的日常工作方式。尤其当项目需要直接在服务器上运行或本地计算资源有限时,能够使用一款便捷、强大的工具至关重要。在众多 IDE 中,VSCode 因其轻量、灵活且支持丰富插件,成为远程开发的理想选择。本文将详细介绍如何通过…

【Vue3】状态仓库持久化

前言 由于 vuex 和 pinia 是将数据存储到内存中的&#xff0c;所以刷新页面后数据会丢失。如果想要持久化存储&#xff0c;就需要将数据同步到 WebStorage。可以使用现有的插件或者自己手写一个插件&#xff0c;本文对二者均有介绍。 其中手写插件案例使用两个简单模块&#…

【PyTorch】图像目标检测

图像目标检测是什么 Object Detection 判断图像中目标的位置 目标检测两要素 分类&#xff1a;分类向量 [p0, …, pn]回归&#xff1a;回归边界框 [x1, y1, x2, y2] 模型如何完成目标检测 将3D张量映射到两个张量 分类张量&#xff1a;shape为 [N, c1]边界框张量&#xf…

【选择”丹摩“深入探索智谱AI的CogVideoX:视频生成的新前沿】

文章目录 一、CogVideoX模型概述二、变革性的3D变分自编码器三、先进的3D旋转位置编码四、端到端的视频理解模型五、丹摩平台的环境配置简单介绍六、开发者的展望示例代码&#xff1a;与CogVideoX的交互 2024年8月6日&#xff0c;智谱AI宣布其开源视频生成模型CogVideoX&#x…

16、斑马设备的ppocer-4进行文字识别和opencv-mobile中文显示

基本思想:手上有个斑马设备,是客户的,简单记录一下开发过程和工程项目,同时记录跟着android小哥学习了很多anroid的知识,转ppocr-4参考之前的ppocr-3转换即可,整个框架仍然使用c++ ncnn jni框架推理和现实,图像库使用opencv-mobile 一、首先转paddle-cor-4 到ncnn的框架…

E34.【C语言】位段练习题

1.题目 分析下列代码中位段在内存中的排布(已知测试平台为VS2022) struct S {int a : 2;int b : 5;int c : 10;int d : 30; };int main() {struct S s { 0 };return 0; } 有关位段的知识点见64.【C语言】再议结构体(下)文 2.提示 VS满足:由低地址向高地址存储,按浪费空间…

新书推荐——《深度学习精粹与PyTorch实践》

深度学习绝非不可窥探的黑箱!深入理解其模型和算法的实际运作机制&#xff0c;是驾驭并优化结果的关键。你无需成为数学专家或资深数据科学家,同样能够掌握深度学习系统内部的工作原理。 本书旨在通过深入浅出的方式&#xff0c;为你揭示这些原理&#xff0c;让你在理解和解释…

C++系列-继承

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 继承的概念和定义 继承是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行拓展&#xff0c;增加功能&#xff0c;这样可以…

SSL VPN | Easyconnect下载安装使用 (详尽)

EasyConnect是一款远程连接工具&#xff0c;为用户提供简便、快捷的远程访问和控制解决方案。 目录 下载 安装 使用 卸载 下载 通过链接进入官网技术支持板块 深信服技术支持-简单、高效、自助化服务 (sangfor.com.cn)https://support.sangfor.com.cn/ 选择软件下载 在安…

获取本函数所在代码域内的所有局部变量和值以字典形式返回locals()

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 获取本函数所在代码域内的 所有局部变量和值 以字典形式返回 locals() 选择题 关于以下代码输出的结果说法正确的是&#xff1f; a 10 def x(): b 20 print(locals()) print("【执行…

二值图像的面积求取的两种方法及MATLAB实现

一、引言 面积在数字图像处理中经常用到&#xff0c;在MATLAB中&#xff0c;计算二值图像的面积通常可以通过两种主要方法实现&#xff1a;遍历法和直接利用bwarea函数。下面将分别介绍这两种方法的原理和相应的MATLAB代码示例。 二、遍历法计算二值图像面积的原理和MATLAB代码…

护眼落地台灯品牌前十名:十大全网超高热度品牌汇总

十大护眼路灯台灯有哪些&#xff1f;在众多照明灯具产品中&#xff0c;护眼落地台灯能够提供适合多场景、大氛围的舒适照明&#xff0c;对于学生、工作群体来说能够有效的提高光线质量&#xff0c;减少不良光线带来的近视风险。可是市场品牌繁多&#xff0c;很容易选购到劣质的…