Leetcode 1504. 统计全 1 子矩形

1.题目基本信息

1.1.题目描述

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

1.2.题目地址

https://leetcode.cn/problems/count-submatrices-with-all-ones/description/

2.解题方法

2.1.解题思路

单调栈

时间复杂度:O(n)

2.2.解题步骤

第一步,构建rows矩阵,rows[i][j]表示从mat[i][j]开始向左连续为1的个数(包括本身)

第二步,遍历每一列,列号记为j,再遍历每列中的每行,行号即为i

2.1.构建每一列的维护变量。total维护以(i,j)为右下角的全为1的子矩阵个数(如果该列的rows[i][j]非严格递增,则就等于前缀和);stack维护随着rows[i][j]严格递增的单调栈,存储单元形式为(rows[i][j],height*=rows矩阵中(i,j)上面连续不小于rows[i][j]的个数+1)

2.2.遍历每一列,更新total和stack,并将total更新到结果变量result中。total更新:如果rows[i][j]大于或等于单调栈栈顶的元素,则直接将rows[i][j]增加到total中,并入栈即可;如果小于,则将大的元素从栈中弹出,并从total中切除多余的子矩阵数(相当于切成一个非严格递增的rows[i][j]序列)

3.解题代码

Python代码

class Solution:
    def numSubmat(self, mat: List[List[int]]) -> int:
        # 思路:单调栈
        m, n = len(mat), len(mat[0])
        # 第一步,构建rows矩阵,rows[i][j]表示从mat[i][j]开始向左连续为1的个数(包括本身)
        rows = [[0] * n for _ in range(m)]
        for i in range(m):
            for j in range(n):
                if mat[i][j] == 1:
                    if j > 0:
                        rows[i][j] = rows[i][j - 1] + 1
                    else:
                        rows[i][j] = 1
        # 第二步,遍历每一列,列号记为j,再遍历每列中的每行,行号即为i
        result = 0
        for j in range(n):
            # 2.1.构建每一列的维护变量。total维护以(i,j)为右下角的全为1的子矩阵个数(如果该列的rows[i][j]非严格递增,则就等于前缀和);stack维护随着rows[i][j]严格递增的单调栈,存储单元形式为(rows[i][j],height*=rows矩阵中(i,j)上面连续不小于rows[i][j]的个数+1)
            total = 0
            stack = []
            # 2.2.遍历每一列,更新total和stack,并将total更新到结果变量result中。total更新:如果rows[i][j]大于或等于单调栈栈顶的元素,则直接将rows[i][j]增加到total中,并入栈即可;如果小于,则将大的元素从栈中弹出,并从total中切除多余的子矩阵数(相当于切成一个非严格递增的rows[i][j]序列)
            for i in range(m):
                height = 1
                while stack and stack[-1][0] >= rows[i][j]:
                    preRow, preHeight = stack.pop()
                    height += preHeight
                    total -= (preRow - rows[i][j]) * preHeight
                total += rows[i][j]
                stack.append([rows[i][j], height])
                result += total
        return result

4.执行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Benjamin Tang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值