【LeetCode】统计全 1 子矩形(单调栈)

news/2024/4/29 19:34:19/文章来源:https://blog.csdn.net/cy973071263/article/details/126612766

1504. 统计全 1 子矩形 - 力扣(LeetCode)

一、题目

给你一个 m x n 的二进制矩阵 mat ,请你返回有多少个 子矩形 的元素全部都是 1 。

示例 1:

 

输入:mat = [[1,0,1],[1,1,0],[1,1,0]]
输出:13
解释:
有 6 个 1x1 的矩形。
有 2 个 1x2 的矩形。
有 3 个 2x1 的矩形。
有 1 个 2x2 的矩形。
有 1 个 3x1 的矩形。
矩形数目总共 = 6 + 2 + 3 + 1 + 1 = 13 。 

示例 2:

 

输入:mat = [[0,1,1,0],[0,1,1,1],[1,1,1,0]]
输出:24
解释:
有 8 个 1x1 的子矩形。
有 5 个 1x2 的子矩形。
有 2 个 1x3 的子矩形。
有 4 个 2x1 的子矩形。
有 2 个 2x2 的子矩形。
有 2 个 3x1 的子矩形。
有 1 个 3x2 的子矩形。
矩形数目总共 = 8 + 5 + 2 + 4 + 2 + 2 + 1 = 24 。 

提示:

  • 1 <= m, n <= 150
  • mat[i][j] 仅包含 0 或 1

二、代码

class Solution {// 先按行遍历二维数组,生成每一行的直方图public int numSubmat(int[][] mat) {int row = mat.length;int col = mat[0].length;// 用来记录当前遍历到这一行的上一行的直方图高度int[] heights = new int[col];// 记录子矩阵个数int cnt = 0;// 按行遍历二维数组for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {// 生成本行的直方图高度,如果本行为0,则直接将对应位置的高度设置为0,如果不为零,则继承类加上一行直方图的高度heights[j] = mat[i][j] == 0 ? 0 : heights[j] + 1;}// 调用countMatInRow方法,利用单调栈统计当前这一行直方图中有多少个子矩阵cnt += countMatInRow(heights);}return cnt;}// 比如//              1//              1//              1         1//    1         1         1//    1         1         1//    1         1         1//             //    2  ....   6   ....  9// 如上图,假设在6位置,1的高度为6// 在6位置的左边,离6位置最近、且小于高度6的位置是2,2位置的高度是3// 在6位置的右边,离6位置最近、且小于高度6的位置是9,9位置的高度是4// 此时我们求什么?// 1) 求在3~8范围上,必须以高度6作为高的矩形,有几个?// 2) 求在3~8范围上,必须以高度5作为高的矩形,有几个?// 也就是说,<=4的高度,一律不求// 那么,1) 求必须以位置6的高度6作为高的矩形,有几个?// 3..3  3..4  3..5  3..6  3..7  3..8// 4..4  4..5  4..6  4..7  4..8// 5..5  5..6  5..7  5..8// 6..6  6..7  6..8// 7..7  7..8// 8..8// 这么多!= 21 = (9 - 2 - 1) * (9 - 2) / 2// 这就是任何一个数字从栈里弹出的时候,计算矩形数量的方式public int countMatInRow(int[] heights) {// 创建单调栈int n = heights.length;int top = -1;// 栈中存储的是下标int[] stack = new int[n];// 记录当前这一层直方图中有多少个子矩阵int cnt = 0;// 遍历当前这一行的直方图for (int i = 0; i < n; i++) {// 整个过程就是单调栈的弹出和压入// 如果要压入栈的值小于单调栈栈顶的值,这就会破坏单调栈结构,需要将栈顶元素弹出,收集该元素的信息,得到能左右扩张的最大区域范围while (top != -1 && heights[stack[top]] >= heights[i]) {// 弹出栈顶元素 int index = stack[top--];// 得到左边距离弹出元素最近的并且小于它的值的下标,如果栈中已经没有元素了,说明弹出值的左边已经没有小于它的值了,就赋值为-1// 注意这里如果没有比它小的了,就设置为-1,也就相当于标记上可用大区域的左边界的向左一个为止,用于后续的计算int leftIndex = top == -1 ? -1 : stack[top];// 右边距离弹出元素最近并且小于它的值的下标int rightIndex = i;// 此时我们得到最大扩张的大区域范围就是leftIndex~rightIndex之前的范围,不包括下标leftIndex和rightIndex// 选取左右最近的比自己小的最大值,注意这里要讨论top == -1的情况int maxHeight = top == -1 ? heights[rightIndex] : Math.max(heights[leftIndex], heights[rightIndex]);// 这里要统计高度heights[index] ~ maxHeight+1 的矩阵的所有可能情况// 每一种高度可能的情况就有((1 + n) * n) >> 1中,n为当前大区域的宽度,其实就是求一个等差数列// 大区域宽度 = rightIndex - leftIndex - 1cnt += (heights[index] - maxHeight) * computeLength(rightIndex - leftIndex - 1);}// 将新的直方图下标加入单调栈stack[++top] = i;}// 单独处理栈中剩余的元素while (top != -1) {// 栈中剩余的元素他们的右边已经没有比他们小的值了// 弹出栈顶int index = stack[top--];// 得到左边距离弹出元素最近的并且小于它的值的下标,如果栈中已经没有元素了,说明弹出值的左边已经没有小于它的值了,就赋值为-1int leftIndex = top == -1 ? -1 : stack[top];// 此时弹出的值的右边已经没有比他小的元素了,所以这里直接设置成n,也就是边界下标n-1的右边一个位置,这样方便后面计算子矩阵个数int rightIndex = n;// 选取左右最近的比自己小的最大值,注意这里要讨论top == -1的情况int maxHeight = top == -1 ? 0 : heights[leftIndex];// 此时我们得到最大扩张的大区域范围就是leftIndex~n之前的范围,不包括下标leftIndex和ncnt += (heights[index] - maxHeight) * computeLength(rightIndex - leftIndex - 1);}return cnt;}// 计算指定n宽度的大区域内,固定高度的子矩阵一共有多少个public int computeLength(int n) {// 这个计算结果一定是偶数(存在一个(n + 1) * n 的操作),所以可以通过右移1位计算出精确的除以2的结果return ((1 + n) * n) >> 1;}
}

三、解题思路 

整个题可以利用LeetCode 85题的思路,先将每一行转换成直方图进行数组压缩,然后再利用单调栈求出所有的最大连通矩阵,得到了最大连通矩阵就可以在每一个矩阵内部求子矩阵的数量了。

其实这道题优化够好的话,暴力模拟也是可以过的。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCL基础学习 字符串

基本指令 Tcl将所有的变量值视作字符串&#xff0c;并将他们作为字符串来保存。下标列出了比较有用的字符串操作命令&#xff1a; append将值追加到字符串尾binary二进制字符串操作format字符串格式化regexp正则表达式regsub用字符串模式进行字符串模拟匹配和替换scan字符串分…

计算机网络面试(一)网络分层结构

文章目录为什么使用分层结构OSI参考模型分层结构——OSI参考模型ISO各个分层解析TCP/IP各个分层解析为什么使用分层结构 对网络分层以后&#xff0c;可以将问题细化&#xff0c;使得问题更加容易分析。把一个大的系统分拆成小的体系后&#xff0c;便于在各个层次上制定标准&am…

《三叶虫与其他故事》我的恐惧如涟漪扩散,荡漾过百万年的时光

《三叶虫与其他故事》我的恐惧如涟漪扩散&#xff0c;荡漾过百万年的时光 布里斯D’J.潘凯克 Breece D‘J Pancake&#xff08;1952-1979&#xff09;&#xff0c;美国作家。二十六岁时自杀身亡&#xff0c;生前仅发表过六篇小说。潘凯克深受美国南方文学传统的影响&#xff0c…

3dmax的Corona的渲染器材质要如何完全转换VRay材质?

经常有伙伴问怎么转化材质&#xff0c;将CR转换成vr或者将VR转换CR~其实这一点需要通过材质转换插件即可转换~ 方法一&#xff1a;cr转vr材质&#xff0c;自带 第一步&#xff1a;确认自己的corona渲染器版本为corona5及以上&#xff1a; ​ 第2步 确认自己的vray渲染器版本…

springboot手机推荐网站毕业设计源码052329

摘 要 随着社会的发展&#xff0c;计算机的优势和普及使得手机推荐网站的开发成为必需。手机推荐网站主要是借助计算机&#xff0c;通过对首页、手机问答、公告消息、手机资讯、手机测评、我的、跳转到后台等信息进行管理。减少管理员的工作&#xff0c;同时也方便广大用户对个…

voip|网络电话,软件实现电信座机

原理 我们办理的宽带一般都含有座机服务&#xff0c;有一个座机号&#xff0c;自己买个座机插到光猫的语音口上就能用。光猫内置语音服务&#xff0c;座机通过电话线接上光猫来打电话&#xff0c;这个语音服务本质上是VOIP&#xff0c;基于IP的语音传输&#xff0c;光猫在VOIP…

Python输入漏洞利用(Python input漏洞)

背景条件 源码为python编写的程序该程序包含input函数&#xff0c;利用用户或自动化输入获取参数进行下一步 漏洞函数 input()&#xff1a;接收用户输入且不修改输入的类型raw_input()&#xff1a;接收用户输入并强制修改为字符串类型 漏洞源码示例 #!/usr/bin/python3 #-*- …

Revit中模板类图元使用后如何处理?

Revit中模板类图元使用后如何处理? 模板这类图元在使用结束后进行拆除的在正常建模形之后它就会一直存在虽然我们可以进行视图处理&#xff0c;但是新建立视图还会显示这类图元&#xff0c;我们可以用其他方法处理它么? 这里我们可以用阶段化来控制&#xff0c;这里以小别墅为…

通过配置文件修改docker容器端口映射

有时候&#xff0c;我们需要给正在运行的容器添加端口映射&#xff0c;百度一下发现很多都是通过iptables&#xff0c;或者是通过将当前容器通过docker commit命令提交为一个镜像&#xff0c;然后重新执行docker run命令添加端口映射。这种方法虽然可以&#xff0c;但是感觉好像…

java基于ssm课程建设制作服务平台系统

1.分管理员和客户,分别有注册账号,修改密码,等功能。2.管理员模块可以在不同的专业专栏上传视频,word文稿,并修改视频名,文稿,视频的增删功能,并给视频标注A B C三个等级3.用户可以在不同的专业专栏观看视频&#xff08;可以看到abc等级&#xff09;,可以下载管理员所上传文稿,…

【图解HTTP】HTTP协议基础

【HTTP协议用于客户端和服务器端之间的通信】 【客户端】请求访问文本或图像等资源的一段 【服务器端】提供资源响应的一端 客户端发送请求&#xff0c;服务器端回复响应 从客户端开始建立通信的&#xff0c;服务器端在没有接受到请求之前不会发送响应。 【请求报文】 【响…

Python 测试开发 20+ 项目实战,提升 5 大测试核心技能

⬇️ 点击“下方链接”,提升测试核心竞争力! >>更多技术文章分享和免费资料领取 软件测试行业从业门槛越来越高,传统手工测试人员逐渐被淘汰,而 测试开发工程师 则供不应求,成为 BAT 互联网大厂高薪求聘的稀缺人才,年薪 30W+ 起,年薪 50W-100W+ 也很常见,甚至超越…

【vue3】03. 跟着官网学习vue3

每日鸡汤&#xff1a;所有真实的快乐&#xff0c;都来自很久的努力 前言 这一节我们主要学习【模版语法】相关的知识&#xff0c;上一节&#xff0c;我们说到根目录下面的index.html是我们的根组件模版&#xff0c;所以可见模版语法是基于html的。 一、模版基本语法 1. 使用…

人工智能+工业互联网,如何破圈?

如何破圈&#xff1f; 2022年奥密克戎的袭击还没阻断&#xff0c;金三银四的寒冬还没挺过&#xff0c;大厂裁员就喧嚣尘上&#xff0c;内卷的战争愈演愈烈。 但我认为&#xff0c;自身有一些加分项&#xff0c;对于还击压力还是能有一些优势。 对于每位开发者来说&#xff0c…

Python进阶(三)-图形界面编程Tkinter(3)

三、Tkinter创建图像界面3 3.1 组件介绍 3.1.1 Listbox列表框 首先介绍一下列表框&#xff0c;即 Listbox。在使用 Tkinter 进行 GUI 编程的过程中&#xff0c;如果需要用户自己进行选择时就可以使用列表框控件。列表框中的选项可以是多个条目&#xff0c;也可以是单个唯一条…

Jenkins持续集成部署-配置Harbor机器人账号推送镜像

Jenkins持续集成部署-配置Harbor机器人账号推送镜像 前言1. 新建 Harbor 机器人账号2. 配置到 Jenkins 全局凭证中3. 配置全局参数后记前言 在某些情况下,为了 Harbor仓库的安全性考虑,在 流水线任务中直接配置用户的话,后面还要维护其权限,命名项目是公开的了,登录成功 …

[Java]快速入门二叉树,手撕相关面试题

专栏简介 :java语法及数据结构 题目来源:leetcode,牛客,剑指offer 创作目标:从java语法角度实现底层相关数据结构,达到手撕各类题目的水平. 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录 前言 一>树形结…

第三方库

Python拥有活跃的贡献者和用户支持社区,并且根据开放源代码许可条款,其软件可供其他Python开发人员使用,这是python之所以这么受欢迎的原因之一。 第三方库就是非python自带的,由其他人写的python模块。 pypi是python官方的第三方库仓库,所有人都可以下载第三方库或上传自…

Mach-O详解(一) - 破题

什么是Mach-O Mach-O: Mach Object 布拉布拉…&#xff0c;概念没意思&#xff0c;反正就是一可执行文件 ios中的常见的.o .a .dylib Framework dyld dsym 都是Mach-O 抽象概念 是一种可执行文件&#xff0c;用于目标代码&#xff0c;动态库&#xff0c;内核转储 每个Mac…

今天来说说Java开发中常用的框架有哪些?

什么是框架 “框架&#xff08;Framework&#xff09;”一词最早出现在建筑领域&#xff0c;指的是在建造房屋前期构建的建筑骨架。在编程领域&#xff0c;框架就是应用程序的骨架&#xff0c;开发人员可以在这个骨架上加入自己的东西&#xff0c;搭建出符合自己需求的应用系统…