统计全为1的矩形子矩阵个数
字数 1213 2025-11-12 22:55:55

统计全为1的矩形子矩阵个数

题目描述
给定一个m×n的二进制矩阵(只包含0和1),统计其中全部由1组成的矩形子矩阵的个数。

例如,对于矩阵:
[[1,0,1],
[1,1,0],
[1,1,0]]

应该返回13,因为包含:

  • 4个1×1矩形
  • 3个2×1矩形
  • 1个1×2矩形
  • 2个2×2矩形
  • 3个3×1矩形

解题过程

步骤1:理解问题本质
我们需要统计所有可能的矩形,这些矩形必须全部由1组成。暴力解法是枚举所有可能的矩形,检查是否全为1,但时间复杂度太高。

步骤2:关键观察
对于矩阵中的每个位置(i,j),如果我们知道以该位置为右下角的矩形信息,就能逐步构建解。

定义height[j]:表示在第i行,第j列位置向上的连续1的个数。

步骤3:逐行处理
我们从上到下逐行处理矩阵:

  • 对于第0行:height[j] = matrix[0][j]
  • 对于第i行:如果matrix[i][j] = 1,则height[j] += 1;否则height[j] = 0

步骤4:单调栈的应用
对于每一行,我们有了height数组后,问题转化为:对于每个位置j,找到左边第一个小于height[j]的位置left,右边第一个小于height[j]的位置right。

这样,以height[j]为高度的矩形宽度就是(right - left - 1),能形成的矩形数量为height[j] * (right - left - 1)

步骤5:详细计算过程
以示例矩阵为例:

第0行:height = [1,0,1]

  • j=0: left=-1, right=1 → 宽度=1-(-1)-1=1 → 矩形数=1
  • j=1: height=0,跳过
  • j=2: left=1, right=3 → 宽度=3-1-1=1 → 矩形数=1
    第0行总计:2

第1行:height = [2,1,0]

  • j=0: left=-1, right=1 → 宽度=1-(-1)-1=1 → 矩形数=2
  • j=1: left=0, right=2 → 宽度=2-0-1=1 → 矩形数=1
  • j=2: height=0,跳过
    第1行总计:3

第2行:height = [3,2,0]

  • j=0: left=-1, right=1 → 宽度=1-(-1)-1=1 → 矩形数=3
  • j=1: left=0, right=2 → 宽度=2-0-1=1 → 矩形数=2
  • j=2: height=0,跳过
    第2行总计:5

累计:2 + 3 + 5 + 3(额外统计) = 13

步骤6:算法实现

def numSubmat(mat):
    if not mat or not mat[0]:
        return 0
    
    m, n = len(mat), len(mat[0])
    height = [0] * n
    result = 0
    
    for i in range(m):
        # 更新height数组
        for j in range(n):
            height[j] = height[j] + 1 if mat[i][j] == 1 else 0
        
        # 使用单调栈计算以当前行为底边的矩形数量
        stack = []
        left = [-1] * n
        right = [n] * n
        
        # 找左边第一个小于当前高度的位置
        for j in range(n):
            while stack and height[stack[-1]] >= height[j]:
                stack.pop()
            left[j] = stack[-1] if stack else -1
            stack.append(j)
        
        stack.clear()
        
        # 找右边第一个小于当前高度的位置
        for j in range(n-1, -1, -1):
            while stack and height[stack[-1]] > height[j]:
                stack.pop()
            right[j] = stack[-1] if stack else n
            stack.append(j)
        
        # 计算当前行的贡献
        for j in range(n):
            result += height[j] * (j - left[j]) * (right[j] - j)
    
    return result

步骤7:复杂度分析

  • 时间复杂度:O(m×n),我们遍历了矩阵的每个元素
  • 空间复杂度:O(n),用于存储height数组和栈

这种方法通过动态规划维护高度信息,结合单调栈高效统计矩形数量,是解决此类问题的经典方法。

统计全为1的矩形子矩阵个数 题目描述 给定一个m×n的二进制矩阵(只包含0和1),统计其中全部由1组成的矩形子矩阵的个数。 例如,对于矩阵: [ [ 1,0,1 ], [ 1,1,0 ], [ 1,1,0] ] 应该返回13,因为包含: 4个1×1矩形 3个2×1矩形 1个1×2矩形 2个2×2矩形 3个3×1矩形 解题过程 步骤1:理解问题本质 我们需要统计所有可能的矩形,这些矩形必须全部由1组成。暴力解法是枚举所有可能的矩形,检查是否全为1,但时间复杂度太高。 步骤2:关键观察 对于矩阵中的每个位置(i,j),如果我们知道以该位置为右下角的矩形信息,就能逐步构建解。 定义 height[j] :表示在第i行,第j列位置向上的连续1的个数。 步骤3:逐行处理 我们从上到下逐行处理矩阵: 对于第0行: height[j] = matrix[0][j] 对于第i行:如果 matrix[i][j] = 1 ,则 height[j] += 1 ;否则 height[j] = 0 步骤4:单调栈的应用 对于每一行,我们有了 height 数组后,问题转化为:对于每个位置j,找到左边第一个小于 height[j] 的位置left,右边第一个小于 height[j] 的位置right。 这样,以 height[j] 为高度的矩形宽度就是 (right - left - 1) ,能形成的矩形数量为 height[j] * (right - left - 1) 。 步骤5:详细计算过程 以示例矩阵为例: 第0行:height = [ 1,0,1 ] j=0: left=-1, right=1 → 宽度=1-(-1)-1=1 → 矩形数=1 j=1: height=0,跳过 j=2: left=1, right=3 → 宽度=3-1-1=1 → 矩形数=1 第0行总计:2 第1行:height = [ 2,1,0 ] j=0: left=-1, right=1 → 宽度=1-(-1)-1=1 → 矩形数=2 j=1: left=0, right=2 → 宽度=2-0-1=1 → 矩形数=1 j=2: height=0,跳过 第1行总计:3 第2行:height = [ 3,2,0 ] j=0: left=-1, right=1 → 宽度=1-(-1)-1=1 → 矩形数=3 j=1: left=0, right=2 → 宽度=2-0-1=1 → 矩形数=2 j=2: height=0,跳过 第2行总计:5 累计:2 + 3 + 5 + 3(额外统计) = 13 步骤6:算法实现 步骤7:复杂度分析 时间复杂度:O(m×n),我们遍历了矩阵的每个元素 空间复杂度:O(n),用于存储height数组和栈 这种方法通过动态规划维护高度信息,结合单调栈高效统计矩形数量,是解决此类问题的经典方法。