当前位置: 首页 > 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就是要…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…...

Vue3 PC端 UI组件库我更推荐Naive UI

一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用&#xff0c;前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率&#xff0c;还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库&#xff08;Naive UI、Element …...

前端调试HTTP状态码

1xx&#xff08;信息类状态码&#xff09; 这类状态码表示临时响应&#xff0c;需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分&#xff0c;客户端应继续发送剩余部分。 2xx&#xff08;成功类状态码&#xff09; 表示请求已成功被服务器接收、理解并处…...

「Java基本语法」变量的使用

变量定义 变量是程序中存储数据的容器&#xff0c;用于保存可变的数据值。在Java中&#xff0c;变量必须先声明后使用&#xff0c;声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例&#xff1a;声明与初始化 public class VariableDemo {publi…...