Skip to main content

5454. 统计全 1 子矩形 [medium]

5454. 统计全 1 子矩形 [medium]

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

给你一个只包含 0 和 1 的 rows * columns 矩阵 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 。

示例 3:

输入:mat = [[1,1,1,1,1,1]]
输出:21

示例 4:

输入:mat = [[1,0,1],[0,1,0],[1,0,1]]
输出:5

提示:

  • 1 <= rows <= 150
  • 1 <= columns <= 150
  • 0 <= mat[i][j] <= 1

通过次数1,924 | 提交次数4,230

First Try

2020-07-05

想到了使用left和upper之类来存储前方1的数量,也能解决横竖一维数组的情况,但是一直搞不定n维数组该如何处理。。

看了题解才知道,甚至都不用使用upper,直接使用left记录就行了。

第一个双周赛就这样挂了,还是字节跳动冠名的。

class Solution(object):
def numSubmat(self, mat):
"""
:type mat: List[List[int]]
:rtype: int
"""
m, n = len(mat), len(mat[0])
left = [[0] * n for _ in range(m)]
upper = [[0] * n for _ in range(m)]
rv = 0
for i in range(m):
for j in range(n):
if mat[i][j] == 1:
left[i][j] = 1
upper[i][j] = 1
if i > 0:
upper[i][j] += upper[i - 1][j]
if j > 0:
left[i][j] += left[i][j-1]
# rv += left[i][j]
# 通过额外的width来判断有效的矩阵,这方法实在太巧了
width = left[i][j]
for k in range(0, upper[i][j]):
# print(i, j, k, width, rv)
# i,j的位置写错了一次,调试一个3*3的矩阵都得累死人
width = min(width, left[i-k][j])
rv += width

return rv
  • 执行用时:252 ms, 在所有 Python 提交中击败了100.00%的用户
  • 内存消耗:13 MB, 在所有 Python 提交中击败了100.00%

Failed Version

2020-07-05

失败的版本,N维数组部分全崩了,一直没法覆盖到所有情况,浪费了一个小时。

class Solution:
def numSubmat(self, mat: List[List[int]]) -> int:
m, n = len(mat), len(mat[0])
genzero = lambda: [0, 0, 0]
ones = [[genzero()] * n for _ in range(m)] # (left ones, upper ones, multiones)
# for i in range(m):
# ones[i][0] = [1, ]
rv = 0
for i in range(m):
for j in range(n):
if mat[i][j] == 1:
rv += 1 # 单独一个1元素
ones[i][j] = [1, 1, 0]
if j >= 1:
rv += ones[i][j-1][0] # 前面的n个1,可以额外组成n个一维列表
ones[i][j][0] += ones[i][j-1][0]
if i >= 1:
rv += ones[i-1][j][1] #前面n个1,可以额外组成n个一维列表
ones[i][j][1] += ones[i-1][j][1]
if i >= 1 and j >= 1 and ones[i][j][0] >= 2 and ones[i][j][1] >=2 and ones[i][j-1][1] >=2: # 准备处理矩阵模式了
# 检查能够往左和往右上沿多少个为1
# ones[i][j][2] = 1 + ones[i-1][j][2] + ones[i][j-1][2] - min(ones[i-1][j-1][2], (ones[i][j-1][2] - 1) * (ones[i-1][j][2] - 1))
ones[i][j][2] = 1 + ones[i-1][j][2] + ones[i][j-1][2] - min(ones[i-1][j-1][2], (ones[i][j-1][2] - 1) * (ones[i-1][j][2] - 1) + 1)
rv += ones[i][j][2]
print(ones)
return rv