算法39:统计全 1 子矩形(力扣1504)----单调栈

题目: 

给你一个 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. 假设 数组为 1 0 1, 我们知道它只有2个矩形

2 .那么如果数组变成了:

        1 0 1

        1 1 0.

我们知道第一行只有2个,

第二行可以是下标为0的{1}, 下标为1的{1}, 下标0和1的组合{1,1} 因此累计是3个; 但是,我们还发现第一行和第二行的第一列也可以组成一个矩形。 因此,第二行累计多出了4个矩形

3. 假设数组再增加一行:

此时,第三行单独新增了3个矩形。

但是第三行和第二行组合:

即第二行和第三行的第一列组成一个矩形;

第二行和第三行的第二列组成一个矩形;

第二行和第三行的第一列与第二列也可以组成一个矩形;

不仅如此,第一行、第二行、第三行的第一列也可以组成一个矩阵;

因此,第三行新增的矩阵个数为(3+1+1+1+1)= 7个。

总矩形数量就是 2 + 4 + 7 = 13个。

单调栈:单调栈结构可以快速的找到任意一个数左、右侧比自己大(或小)的数字的下标。

我们按照单调栈的思想,把以上的数组再推导一遍。此时,数组是:

1 0 1

1 1 0

1 1 0

第一行 2个矩形

数组压缩以后,第二行变成 2 1 0.

高度为2只有1个矩形;

高度为1,可以得到下标0和1.  (2-1)* (2 * (2+1)/2 )= 3个

因此第二行累计是 1 + 3 = 4个矩形。

第三行数组压缩以后变成 3 2 0

高度为3的只有1个矩形

高度为2,2*(2*(2+1)/2)= 6个

因此,这个数组累计矩形为 2 + 4 + (1+6)= 13 个矩形

如果还不理解,我再举个例子

假设数组为 1 1 1, 我们根据公式可得  3 * (3+1)/2 = 6;

假设再增加一行:

1 1 1

1 1 1

第一行是6个;

第二行是 3 * (3+1)/2 = 6;但是,第一行和第二行联合起来,还可以拼 3 * (3+1)/2 = 6; 也就是说第二行实际新增了 2*6= 12;

假设再增加一行:

1 1 1

1 1 1

1 1 1

那第一行是 1* 3 * (3+1)/2 = 6;

第二行是     2* 3 * (3+1)/2 = 12;

第三行就是 3 *  3 * (3+1)/2 = 18个;

1对应1行,2对应2行,3对应3行。

现在用压缩数组的角度再来看:

第一行 1 1 1.  根据 1* 3 * (3+1)/2 = 6

第二行变成了 2 2 2. 根据 2* 3 * (3+1)/2 = 12

第三行变成了 3 3 3 根据 3* 3 * (3+1)/2 = 18

有没有发现,公式前面的 1 2 3和压缩数组的数组元素高度出奇的一致?

现在把数组变化一下,左侧是原始数组,右侧是进行数组压缩后的结果

1 1 1 0   ===  1 1 1 0

1 1 1 0  ==== 2 2 2 0

1 1 1 0  ==== 3 3 3 0

1 1 1 1 ==== 4 4 4 1

那第一行是 1* 3 * (3+1)/2 = 6;

第二行是     2* 3 * (3+1)/2 = 12;

第三行就是 3 *  3 * (3+1)/2 = 18个;

第四行就要分情况了:

首先:以高度为4的情况,可得 3 * (3+1)/2 = 6

其次,以高度为3的情况,可得 3 * (3+1)/2 = 6

然后,以高度为2的情况, 可得  3 * (3+1)/2 = 6

最后,以1为高度的情况,注意,此时以高度为1的情况长度为4,  4 *(4+1)/2 = 10;

总的概括,第四行就是前三行的组合:

第四行与前三行组合不就是 (4-1)*(3 * (3+1)/2 )= 3* 6 = 18个矩形

第四行单独新增   (1-0)* (4 *(4+1)/2 = 10;

因此,最终矩形数量为 : 6 + 12 +  18 + (6+6+6+10)= 64个矩形;

package code04.单调栈_01;/*** 力扣1504, 统计全1矩阵* https://leetcode.com/problems/count-submatrices-with-all-ones*/
public class Code05_SumOfRectangleForAllOne {public int numSubmat(int[][] mat){if (mat == null || mat.length == 0) {return 0;}int sum = 0;int[] help = new int[mat[0].length];for (int i = 0; i < mat.length; i++) {for (int j = 0; j < mat[i].length; j++) {//数组压缩help[j] = mat[i][j] == 0 ? 0 : help[j] + 1;}sum += countRectangle(help);}return sum;}public int countRectangle(int[] help){int size = help.length;//自定义栈结构int[] stack = new int[size];int stackSize = 0;int ans = 0;for (int i = 0; i < size; i++){//如果栈中元素比当前数组i对应的数据大,弹出栈中数据while (stackSize != 0 && help[stack[stackSize-1]] > help[i]) {//弹出栈顶元素int cur = stack[--stackSize];//左侧比弹出的cur小的位置int left = stackSize == 0 ? -1 : stack[stackSize -1];//确保单调栈的连通性,获取左、有两侧比当前cur小的值中较大的数int max = Math.max(left == -1 ? 0 : help[left],  help[i]);//统计cur作为最小值的范围int quantity = i - 1 - left;/*** help[cur] - max 代表高度中高出的部分. 比如* 1 0 1 中有2个矩形** 再增加一行* 1 0 1   = 2个* 1 1 0   = 4个* 此时数组压缩成了2 1 0* 此时的 help[cur] - max就代表 2 - 1. 即高度为2的部分单独算* 而count(quantity) 就代表高度为2的连续元素有多少个** 根据压缩后的数组 2, 1, 0,推导第二行矩形个数* 先以高度为2的计算 (2-1) * (1*(1+1)/2) = 1个* 再以高度为1的计算 (1-0) * (2*(2+1)/2) = 3个* 合计 1+3 =4个*** 如果在增加一行*  1 0 1      = 2 个矩形*  1 1 0      = 4 个矩形*  1 1 1      = 10 个矩形*  最后一行数组压缩成 3 2 1*  先算高度为3的 (3 - 2)* (1*(1+1)/2) = 1个*  再算高度为2的 (2 - 1) * (2*(2+1)/2) = 3个*  最后算高度为1的 (1-0) * (3*(3+1)/2) = 6个*  合计 1+ 3 + 6 = 10个** 那么,如果数组为*  1 0 1*  1 1 0*  1 1 1**  那么,总的矩形就是 2 + 4 + 10 = 16个**/ans += (help[cur] - max) * count(quantity);}stack[stackSize++] = i;}while (stackSize != 0) {//弹出栈顶元素int cur = stack[--stackSize];//左侧比弹出的cur小的位置int left = stackSize == 0 ? -1 : stack[stackSize -1];//确保单调栈的连通性int max = Math.max(left == -1 ? 0 : help[left], 0);//统计cur作为最小值的范围int quantity = size - 1 - left;ans +=  (help[cur] - max)  * count(quantity);}return ans;}public int count (int n) {return n * (n+1) >> 1;}public static void main(String[] args) {Code05_SumOfRectangleForAllOne ss = new Code05_SumOfRectangleForAllOne();int[][] mat = {{1,0,1},{1,1,0},{1,1,1}};System.out.println(ss.numSubmat(mat));}
}

测试结果

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

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

相关文章

ERP定制费用怎么算?详解跨境电商成本控制策略

在全球化数字经济的浪潮中&#xff0c;跨境电商行业具有潜在的高利润和巨大的发展空间&#xff0c;吸引着众多创业者的关注和投入。然而&#xff0c;与潜在利润相伴随的是种种挑战&#xff0c;成本控制便是其中关键的一环。在这一行业中&#xff0c;ERP定制费用作为一个重要的成…

第十三章认识Ajax(四)

认识FormData对象 FormData对象用于创建一个表示HTML表单数据的键值对集合。 它可以用于发送AJAX请求或通过XMLHttpRequest发送表单数据。 以下是FormData对象的一些作用&#xff1a; 收集表单数据&#xff1a;通过将FormData对象与表单元素关联&#xff0c;可以方便地收集表…

C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现

C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现 —— 杭州 2024-01-28 code review! 文章目录 C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现1.RTTI、RAII、MVC、MVVM、SOLID简述2.RAII (Resource Acquisition Is Initialization)3.RTTI (Run-Time Type Informat…

Springboot响应数据详解

功能接口 Controller下每一个暴露在外的方法都是一个功能接口 功能接口的请求路径是RequestMapping定义的路径&#xff0c;浏览器需要请求该功能则需要发出该路径下的请求。 RestController RestControllerControllerResponseBody(响应数据的注解) ResponseBody 类型&#…

【数据分析】numpy基础第二天

文章目录 前言数组的形状变换reshape的基本介绍使用reshapereshape([10, 1])运行结果reshape自动判断形状reshape([-1, 1])运行结果 合并数组使用vstack和hstackvstack和hstack的运行结果使用concatenateconcatenate运行结果 分割数组array_split运行结果 数组的条件筛选条件筛…

Matlab|【完全复现】基于价值认同的需求侧电能共享分布式交易策略

目录 1 主要内容 2 部分程序 3 程序结果 4 下载链接 1 主要内容 该程序完全复现《基于价值认同的需求侧电能共享分布式交易策略》&#xff0c;针对电能共享市场的交易机制进行研究&#xff0c;提出了基于价值认同的需求侧电能共享分布式交易策略&#xff0c;旨在降低电力市…

腾讯云幻兽帕鲁服务器创建教程,附4核16G服务器价格表

腾讯云0基础搭建帕鲁服务器4C16G14M服务器稳定无卡顿&#xff0c;先下载SteamCMD&#xff0c;并运行&#xff1b;然后下载Palserver&#xff0c;修改服务ini配置&#xff0c;启动PalServer&#xff0c;进入游戏服务器。腾讯云百科txybk.com分享腾讯云创建幻兽帕鲁服务器教程&am…

写点东西《JWT 与会话身份验证》

写点东西《JWT 与会话身份验证》 身份验证与授权 JWT 与session身份验证 - 基本差异 什么是 JWT&#xff1f; JWT 结构&#xff1a; JWT 工作流程&#xff1a;优势: 安全问题&#xff1a; 处理令牌过期&#xff1a; 基于session的身份验证&#xff08;通常称为基于 cookie 的身…

深度强化学习(王树森)笔记07

深度强化学习&#xff08;DRL&#xff09; 本文是学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。本文在ChatGPT辅助下完成。 参考链接 Deep Reinforcement Learning官方链接&#xff1a;https://github.com/wangshusen/DRL 源代码链接&#xff1a;https://github.c…

Qt|大小端数据转换

后面打算写Qt关于网络编程的博客&#xff0c;网络编程就绕不开字节流数据传输&#xff0c;字节流数据的传输一般是根据协议来定义对应的报文该如何组包&#xff0c;那这就必然牵扯到了大端字节序和小端字节序的问题了。不清楚的大小端的可以看一下相关资料&#xff1a;大小端模…

【华为 ICT HCIA eNSP 习题汇总】——题目集11

1、某公司的内网用户采用 NAT 技术的 NO-pat 方式访问互联网&#xff0c;若所有的公网地址均被使用&#xff0c;则后续上网的内网用户会&#xff08;&#xff09;。 A、挤掉前一个用户&#xff0c;强制进行 NAT 转换上网 B、将报文同步到其他 NAT 转换设备上进行 NAT 转换 C、自…

springboot集成 Redis快速入门demo

一、准备redis环境 这里用docker-compose来搭建Redis测试环境&#xff0c;采用单机模式&#xff0c;具体配置如下&#xff1a; docker-compose-redis.yml version: 3 services:redis:image: registry.cn-hangzhou.aliyuncs.com/zhengqing/redis:6.0.8 # ima…

牛客周赛30

思路&#xff1a;先把x, y除以最大公约数变成最小值&#xff0c;然后同时乘以倍数cnt&#xff0c;只记录两个数都在[l,r]间的倍数。 代码&#xff1a; int gcd(int a,int b){return b ? gcd(b, a % b) : a; }void solve(){int x, y, l, r;cin >> x >> y >>…

ubuntu中的rsyslog

目录 1. rsyslog简介 2. 查看/var/log 3. syslog的配置文件 3.1 /etc/rsyslog.d/50-default.conf 3.2 /etc/rsyslog.conf 4. 如何写入syslog 4.1 C语言 4.2 shell 4.3 内核输出 5. syslog.1和syslog.2.gz等文件是如何生成 6. logrotate是如何被执行 7. 如何限制sys…

【网络】WireShark过滤 | WireShark实现TCP三次握手和四次挥手

目录 一、开启WireShark的大门 1.1 WireShark简介 1.2 常用的Wireshark过滤方式 二、如何抓包搜索关键字 2.1 协议过滤 2.2 IP过滤 ​编辑 2.3 过滤端口 2.4 过滤MAC地址 2.5 过滤包长度 2.6 HTTP模式过滤 三、ARP协议分析 四、WireShark之ICMP协议 五、TCP三次握…

Jmeter学习系列之一:Jmeter的详细介绍

目录 一、Jmeter的介绍 二、Jemeter的特点 三、Jemter相关概念 3.1采样器&#xff08;Samplers&#xff09; 3.2逻辑控制器&#xff08;Logic Controllers&#xff09; 3.3监听器&#xff08;Listeners&#xff09; 3.4配置元件&#xff08;Configuration Elements&#…

Mac安装配置maven

Mac安装配置maven 官网下载地址&#xff1a;https://maven.apache.org/download.cgi 下载好以后解压配置 maven 环境变量 打开终端&#xff0c;输入命令打开配置文件./bash_profile open ~/.bash_profile输入i进入编辑模式,进行maven配置; MAVEN_HOME为maven的本地路径 ex…

Phoncent博客GPT写作工具

对于许多人来说&#xff0c;写作并不是一件轻松的事情。有时候&#xff0c;我们可能会遇到写作灵感枯竭、写作思路混乱、语言表达困难等问题。为了解决这些问题&#xff0c;Phoncent博客推出了一款创新的工具——GPT写作工具&#xff0c;它利用了GPT技术&#xff0c;为用户提供…

Springboot入门教程详解

Springboot入门教程详解 博客主页&#xff1a;划水的阿瞒的博客主页 欢迎关注&#x1f5b1;点赞&#x1f380;收藏⭐留言✒ 系列专栏&#xff1a;Springboot入门教程详解首发时间&#xff1a;&#x1f39e;2024年1月29日&#x1f3a0; 如果觉得博主的文章还不错的话&#xff0c…

vue+axios+promise实际开发用法

vueaxiospromise实际开发用法 vuex 核心 & 数据响应式原理 vuex 使用总结&#xff08;详解&#xff09; vue的双向绑定原理及实现 一、axios的介绍 axios 是由 promise 封装的一个 http 的库。 promise是 es6 为解决异步编程的。 什么是异步&#xff1f; 1. 不会按…