【Leetcode】1504. 统计全 1 子矩形

43 阅读1分钟

leetcode-1504.png

构建直方图

我们用一个 height 数组来表示直方图,其中 height[j] 表示矩阵在第 j 列连续 1 的高度。
当遇到 mat[i][j] = 1 时,height[j] 在上一行的基础上加 1;否则就重置为 0。

// row one
mat[0] = [1,0,1]
height = [1,0,1]
// row two
mat[1] = [1,1,0]
height = [2,1,0] 
// row three
mat[2] = [1,1,0]
height = [3,2,0]

可以看到,height 是逐行累积出来的,表示“以当前行为底,每一列的高度”。 例如row = 2的时候,height = [3,2,0],此时在第3行第一列上面1的高度就是3

统计矩阵数量

在有了 height 数组之后,我们只需要计算:以第 i 行为底、以第 j 列为右边界,可以形成多少个全 1 子矩阵

var numSubmat = function (mat) {
    let row = mat.length,
        col = mat[0].length;
    let height = new Array(col).fill(0);
    let res = 0;
    for (let i = 0; i < row; ++i) {
        for (let j = 0; j < col; ++j) {
            height[j] = mat[i][j] === 0 ? 0 : height[j] + 1;
        }
        for (let j = 0; j < col; ++j) {
            let minHeight = height[j];
            for (let k = j; k >= 0 && minHeight > 0; --k) {
                minHeight = Math.min(minHeight, height[k]);
                res += minHeight;
            }
        }
    }
    return res;
};

内层循环的含义

关键部分在于第二层循环:

  • 外层 j 表示“以第 j 列为右边界”。
  • 内层 k 从 j 向左扫描,表示“矩形的左边界”。
  • minHeight 表示区间 [k, j] 内的最小高度,也就是矩形的可用高度。

举个例子:
height = [3,2,0],假设 j = 1(第二列,高度=2)

  • 当 k = 1 时,只考虑单独第 2 列,高度=2,可以形成两个矩形。
  • 当 k = 0 时,考虑区间 [0,1],最小高度 = min(3,2) = 2,可以形成两个更宽的矩形。

所以,以第 1 列为右边界的矩阵数 = 2(单列) + 2(两列) = 4。