当前位置: 首页 > news >正文

LeetCode 1277. 统计全为 1 的正方形子矩阵【动态规划】1613

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

给你一个 m * n 的矩阵,矩阵中的元素不是 0 就是 1,请你统计并返回其中完全由 1 组成的 正方形 子矩阵的个数。

示例 1:

输入:matrix =
[[0,1,1,1],[1,1,1,1],[0,1,1,1]
]
输出:15
解释:
边长为 1 的正方形有 10 个。
边长为 2 的正方形有 4 个。
边长为 3 的正方形有 1 个。
正方形的总数 = 10 + 4 + 1 = 15.

示例 2:

输入:matrix = 
[[1,0,1],[1,1,0],[1,1,0]
]
输出:7
解释:
边长为 1 的正方形有 6 个。 
边长为 2 的正方形有 1 个。
正方形的总数 = 6 + 1 = 7.

提示:

  • 1 <= arr.length <= 300
  • 1 <= arr[0].length <= 300
  • 0 <= arr[i][j] <= 1

解法 动态规划/递推(最优)

本题和 221. 最大正方形 非常类似,使用的方法也几乎相同。

我们用 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 ( i , j ) (i,j) (i,j) 为右下角的正方形的最大边长,那么除此定义之外, d p [ i ] [ j ] = x dp[i][j] = x dp[i][j]=x 也表示 ( i , j ) (i,j) (i,j) 为右下角的正方形的数目为 x x x(即边长为 1 , 2 , . . . , x 1, 2, ..., x 1,2,...,x 的正方形各一个)。在计算出所有的 d p [ i ] [ j ] dp[i][j] dp[i][j] 后,我们将它们进行累加,就可以得到矩阵中正方形的数目

我们尝试挖掘 d p [ i ] [ j ] dp[i][j] dp[i][j] 与相邻位置的关系来计算出 d p [ i ] [ j ] dp[i][j] dp[i][j] 的值。

如上图所示,若对于位置 ( i , j ) (i,j) (i,j) d p [ i ] [ j ] = 4 dp[i][j] = 4 dp[i][j]=4 ,我们将以 ( i , j ) (i,j) (i,j) 为右下角、边长为 4 4 4 的正方形涂上色,可以发现其左侧位置 ( i , j − 1 ) (i, j - 1) (i,j1) ,上方位置 ( i − 1 , j ) (i - 1, j) (i1,j) 和左上位置 ( i − 1 , j − 1 ) (i - 1, j - 1) (i1,j1) 均可以作为一个边长为 4 − 1 = 3 4 - 1 = 3 41=3 的正方形的右下角。也就是说,这些位置的的 d p dp dp 值至少为 3 3 3 ,即:

dp[i][j - 1] >= dp[i][j] - 1
dp[i - 1][j] >= dp[i][j] - 1
dp[i - 1][j - 1] >= dp[i][j] - 1

将这三个不等式联立,可以得到:
min ⁡ ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − 1 ] ) ≥ d p [ i ] [ j ] − 1 \min\big(dp[i][j - 1],\ dp[i - 1][j],\ dp[i - 1][j - 1]\big) \geq dp[i][j] - 1 min(dp[i][j1], dp[i1][j], dp[i1][j1])dp[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 [ i ] [ j − 1 ] dp[i][j - 1] dp[i][j1] d p [ i − 1 ] [ j ] dp[i - 1][j] dp[i1][j] d p [ i − 1 ] [ j − 1 ] dp[i - 1][j - 1] dp[i1][j1] 中的最小值为 3 3 3 ,也就是说, ( i , j − 1 ) (i, j - 1) (i,j1) ( i − 1 , j ) (i - 1, j) (i1,j) ( i − 1 , j − 1 ) (i - 1, j - 1) (i1,j1) 均可以作为一个边长为 3 3 3 的正方形的右下角。我们将这些边长为 3 3 3 的正方形依次涂上色,可以发现,如果位置 ( i , j ) (i,j) (i,j) 的元素为 1 1 1 ,那么它可以作为一个边长为 4 4 4 的正方形的右下角, d p dp dp 值至少为 4 4 4 ,即:
d p [ i ] [ j ] ≥ min ⁡ ( f [ i ] [ j − 1 ] , f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − 1 ] ) + 1 dp[i][j] \geq \min\big(f[i][j - 1], f[i - 1][j], f[i - 1][j - 1]\big) + 1 dp[i][j]min(f[i][j1],f[i1][j],f[i1][j1])+1
将其与上一个不等式联立,可以得到:
d p [ i ] [ j ] = min ⁡ ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − 1 ] ) + 1 dp[i][j] = \min\big(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]\big) + 1 dp[i][j]=min(dp[i][j1],dp[i1][j],dp[i1][j1])+1
这样我们就得到了 d p [ i ] [ j ] dp[i][j] dp[i][j] 的递推式。此外还要考虑边界( i = 0 i = 0 i=0 j = 0 j = 0 j=0)以及位置 ( i , j ) (i,j) (i,j) 的元素为 0 0 0 的情况。

我们按照行优先的顺序依次计算 d p [ i ] [ j ] dp[i][j] dp[i][j] 的值,就可以得到最终的答案。

class Solution {
public:int countSquares(vector<vector<int>>& matrix) {int m = matrix.size(), n = matrix[0].size();vector<vector<int>> dp(m + 1, vector<int>(n + 1));int ans = 0;for (int i = 0; i < m; ++i) {for (int j = 0; j < n; ++j) {if (matrix[i][j] == 1) {dp[i + 1][j + 1] = 1 + min(dp[i][j], min(dp[i][j + 1], dp[i + 1][j]));ans += dp[i + 1][j + 1];}}}return ans;}
};

由于递推式中 d p [ i ] [ j ] dp[i][j] dp[i][j] 只与本行和上一行的若干个值有关,因此空间复杂度可以优化至 O ( N ) O(N) O(N)

class Solution {
public:int countSquares(vector<vector<int>>& matrix) {int m = matrix.size(), n = matrix[0].size();vector<int> dp(n + 1);int ans = 0;int pre = 0, temp = 0;for (int i = 0; i < m; ++i) {for (int j = 0; j < n; ++j) {if (matrix[i][j] == 1) {temp = dp[j + 1];dp[j + 1] = 1 + min(pre, min(dp[j + 1], dp[j]));pre = temp; // pre为dp[i][j]ans += dp[j + 1];} else pre = dp[j + 1], dp[j + 1] = 0; // 注意此时也要记录dp[i][j],并更新dp[i+1][j+1]}}return ans;}
};

复杂度分析:

  • 时间复杂度: O ( m n ) O(mn) O(mn)
  • 空间复杂度: O ( n ) O(n) O(n)

相关文章:

LeetCode 1277. 统计全为 1 的正方形子矩阵【动态规划】1613

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

测试部门来了个00后卷王之王,老油条感叹真干不过,但是...

都说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。 这不&#xff0c;前段时间我们公司来了个00后&#xff0c;工作都没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了…...

360 G800行车记录仪,不使用降压线如何开机,8芯插头的定义。

G800记录仪的插头是这样的&#xff0c;图中标出了线的颜色。其中红色为常电V&#xff0c;黑色为GND负极&#xff0c;黄色为ACC受车是否启动控制。 这个记录仪原装的电源线没有降压功能&#xff0c;所以这里的V是12V。 记录仪内部有电源板&#xff0c;负责将12V降压为5V。 如果…...

vue2踩坑之项目:Swiper轮播图使用

首先安装swiper插件 npm i swiper5 安装出现错误&#xff1a;npm ERR npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: vue/eslint-config-standard6.1.0 npm ERR! Found: eslint-plugin-vue8.7.1 npm ERR! node_modules/esl…...

python经典百题之分桃子

题目:海滩上有一堆桃子&#xff0c;五只猴子来分。第一只猴子把这堆桃子平均分为五份&#xff0c;多了一个&#xff0c;这只 猴子把多的一个扔入海中&#xff0c;拿走了一份。第二只猴子把剩下的桃子又平均分成五份&#xff0c;又多了 一个&#xff0c;它同样把多的一个扔入海中…...

vscode ssh linux C++ 程序调试

vscode调试c++程序相比vs2022要复杂很多,vs2022可以"一键运行调试",vscode则需要自己配置。 ​vscode调试程序时,会在当前工作目录产生.vscode 目录, 该目录有两个重要文件launch.json和tasks.json, 下面介绍两种调试方法: 手动调试和自动调试。 手动调试 不管…...

VUE和Angular有哪些区别?

Vue.js和Angular是两个流行的前端JavaScript框架&#xff0c;它们有一些明显的区别&#xff0c;包括以下几个方面&#xff1a; 1、语言和工具链的选择&#xff1a; Vue.js使用HTML、JavaScript和CSS来创建组件&#xff0c;使得它更容易学习&#xff0c;因为它使用了常见的Web…...

云原生边缘计算KubeEdge安装配置(二)

1. K8S集群部署&#xff0c;可以参考如下博客 请安装k8s集群&#xff0c;centos安装k8s集群 请安装k8s集群&#xff0c;ubuntu安装k8s集群 请安装kubeedge cloudcore centos安装K8S 2.安装kubEedge 2.1 编辑kube-proxy使用ipvs代理 kubectl edit configmaps kube-proxy -…...

SQL多表设计--一对多(外键)

-- 完成部门和员工的-- 选择当前db03 这个数据库use db03;-- 查看当前选中的数据库select database();-- 创建员工表create table tb_emp (id int unsigned primary key auto_increment comment ID,username varchar(20) not null unique comment 用户名,password varchar(32)…...

Stm32_标准库_9_TIM

频率(HZ)是频率的基本单位1HZ是1s的倒数 STM32F103C8T6一般情况给定时器的内部时钟都是72MHz&#xff08;系统主频率&#xff09; TIM基本构成 计数器、预分频器、自动化重装 // 都是16位其中计数器、自动化重装&#xff0c;都是16位换算成10进制范围为[0, 655536] 时间 1 /…...

283. 移动零

283. 移动零 原题 /** 左指针左边均为非零数&#xff1b; 右指针左边直到左指针处均为零。*/ class Solution {public void moveZeroes(int[] nums) {int left 0;int right 0;while(right<nums.length){if(nums[right]!0){swap(nums,left,right);left;}right;}}public v…...

用 HTTP 提交数据,基本就这 5 种方式

网页开发中&#xff0c;向服务端提交数据是一个基本功能&#xff0c;工作中会大量用 xhr/fetch 的 api 或者 axios 这种封装了一层的库来做。 可能大家都写过很多 http/https 相关的代码&#xff0c;但是又没有梳理下它们有哪几种呢&#xff1f; 其实通过 http/https 向服务端…...

基于matlab统计Excel文件一列数据中每个数字出现的频次和频率

一、需求描述 如上表所示&#xff0c;在excel文件中&#xff0c;有一列数&#xff0c;统计出该列数中&#xff0c;每个数出现的次数和频率。最后&#xff0c;将统计结果输出到新的excel文件中。 二、程序讲解 第一步&#xff1a;选择excel文件&#xff1b; [Filename, Pathn…...

近期分享学习心得3

1、全屏组件封装 先看之前大屏端的监控部分全屏代码 整块全屏代码 常规流是下面这种 //进入全屏 function full(ele) {//if (ele.requestFullscreen) {// ele.requestFullscreen();//} else if (ele.mozRequestFullScreen) {// ele.mozRequestFullScreen();//} el…...

前端uniapp如何修改下拉框uni-data-select下面的uni-icons插件自带的图片【修改uniapp自带源码图片/图标】

目录 未改前图片未改前源码未改前通过top和bottom 和修改后图片转在线base64大功告成最后 未改前图片 未改前源码 然后注释掉插件带的代码&#xff0c;下面要的 未改前通过top和bottom 和修改后 找到uni-icons源码插件里面样式 图片转在线base64 地址 https://the-x.cn/b…...

【计算机基础】Git系列3:常用操作

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…...

有哪些值得推荐的Java 练手项目?

大家好&#xff0c;我是 jonssonyan 我是一名 Java 后端程序员&#xff0c;偶尔也会写一写前端&#xff0c;主要的技术栈是 JavaSpringBootMySQLRedisVue.js&#xff0c;基于我学过的技术认真的对每个分享的项目进行鉴别&#xff0c;今天就和大家分享我曾经用来学习的开源项目…...

【Godot】时间线(技能)节点

4.1 游戏中一般都会有各种各样的技能&#xff0c;或者其他需要按一定的时间顺序去执行的功能。 这里我写出了一个时间线节点&#xff0c;就像是在播放动画一样&#xff0c;按一定的阶段去执行某些功能 # # Timeline # # - author: zhangxuetu # - datetime: 2023-09-24 23…...

每日练习-9

目录 1、井字棋 2、密码强度等级 3、二维数组中的查找 4.调整数组奇数偶数 5.旋转数组中的最小元素 6、替换空格 1、井字棋 解析&#xff1a;井字棋有四种情况表示当前玩家获胜&#xff0c;行全为1&#xff0c; 列全为1&#xff0c;主对角全为1&#xff0c; 副对角全为1。遍历…...

微信小程序 -- 页面间通信

前言 今天我们来说下微信小程序的页面间通信&#xff1a; 通过url传参实现页面间单向通信通过getCurrentPages()页面栈实现页面间单向通信通过EventChannel实现页面间双向通信 1、url传参 我们知道页面之间的跳转可以通过路由组件来实现&#xff0c;其中组件的属性url就是要…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...