leetcode--统计全 1 子矩形

 题目是LeetCode第196场周赛的第三题,链接:1504. 统计全 1 子矩形。具体描述:给你一个只包含01rows * 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

 这道题的做法就是枚举以坐标(i,j)为右下角的话有多少个全1矩阵。首先需要做一些预处理,统计每一行上每个位置上在竖方向上有多少个连续的1,所以把经过预处理后的每一行看做一个柱状图的话,每个柱子的高度就代表了这一列有多少个连续的1(以这一列的1为底)。然后要计算全1矩阵的话就会方便很多,因为限定了以(i,j)为右下顶点,所以只需要我们枚举可能的宽度(最小是1,最大是此行到(i,j)为止最长连续1的长度),在每个可能的宽度上,根据可能的最小高度h(就是这个宽度范围内所有柱子的最小高度),可以得到h个全1矩阵(其实就是高分别为12、…、h一共h种),累加到结果上即可。假设行数为m,列数为n,则时间复杂度为 O ( m n 2 ) O(mn^{2}) O(mn2),空间复杂度为 O ( 1 ) O(1) O(1)

 JAVA版代码如下:

class Solution {
    public int numSubmat(int[][] mat) {
        int row = mat.length, col = mat[0].length;
        for (int i = 1; i < row; ++i) {
            for (int j = 0; j < col; ++j) {
                if (mat[i][j] == 0) {
                    continue;
                }
                mat[i][j] = mat[i - 1][j] + 1;
            }
        }
        int result = 0;
        for (int i = 0; i < row; ++i) {
            for (int j = 0; j < col; ++j) {
                if (mat[i][j] == 0) {
                    continue;
                }
                int minHeight = mat[i][j];
                int left = j;
                while (left >= 0 && mat[i][left] > 0) {
                    minHeight = Math.min(minHeight, mat[i][left--]);
                    result += minHeight;
                }
            }
        }
        return result;
    }
}

 提交结果如下:


 Python版代码如下:

class Solution:
    def numSubmat(self, mat: List[List[int]]) -> int:
        height = mat#copy.deepcopy(mat)
        row, col = len(mat), len(mat[0])
        for i in range(1, row):
            for j in range(col):
                if height[i][j] == 1:
                    height[i][j] = height[i - 1][j] + 1
        result = 0
        for i in range(row):
            for j in range(col):
                if height[i][j] == 0:
                    continue
                left = j
                minHeight = height[i][j]
                while left >= 0 and height[i][left] > 0:
                    result += minHeight
                    left -= 1
                    minHeight = min(minHeight, height[i][left])
        return result

 提交结果如下:


 另外还可以通过单调栈省去上面算法需要往前回溯统计矩阵数的步骤,将时间复杂度将为 O ( m n ) O(mn) O(mn),空间复杂度则升为 O ( n ) O(n) O(n)。具体解释见这里或者代码注释。

 JAVA版代码如下:

class Solution {
    public int numSubmat(int[][] mat) {
        int row = mat.length, col = mat[0].length;
        for (int i = 1; i < row; ++i) {
            for (int j = 0; j < col; ++j) {
                if (mat[i][j] == 0) {
                    continue;
                }
                mat[i][j] = mat[i - 1][j] + 1;
            }
        }
        int result = 0;
        for (int i = 0; i < row; ++i) {
            Stack<int[]> stack = new Stack<>();
            int cursum = 0;
            for (int j = 0; j < col; ++j) {
                if (mat[i][j] == 0) {
                    stack = new Stack<>();
                    cursum = 0;
                    continue;
                }
                if (stack.empty() || mat[i][j] > stack.peek()[0]) {
                    stack.push(new int[] {mat[i][j], 1});
                    cursum += mat[i][j];
                    result += cursum;
                }
                else {
                    int curWidth = 1;
                    while (!stack.empty() && stack.peek()[0] >= mat[i][j]) {
                        int[] hw = stack.pop();
                        curWidth += hw[1];
                        cursum -= (hw[0] - mat[i][j]) * hw[1];
                    }
                    stack.push(new int[] {mat[i][j], curWidth});
                    cursum += mat[i][j];
                    result += cursum;
                }
            }
        }
        return result;
    }
}

 提交结果如下:


 Python版代码如下:

class Solution:
    def numSubmat(self, mat: List[List[int]]) -> int:
        height = mat
        row, col = len(mat), len(mat[0])
        for i in range(1, row):
            for j in range(col):
                if height[i][j] == 1:
                    height[i][j] = height[i - 1][j] + 1
        result = 0
        for i in range(row):
            # 高递增的单调栈,存放[高,宽]
            stack = []
            # 累加前面的全1矩阵数
            cursum = 0
            for j in range(col):
                if height[i][j] == 0:
                    stack = []
                    cursum = 0
                    continue
                if not stack or height[i][j] > stack[-1][0]:
                    # 当前高度大于之前的最大高度的话
                    # 那么以当前点为右下角的全1矩阵数就是cursum+当前高度
                    # 其中cursum代表了宽度为2、3...的全1矩阵数
                    stack.append([height[i][j], 1])
                    cursum += height[i][j]
                    result += cursum
                else:
                    # 当前高度比之前的最大高度低的话
                    # 比当前高度高的那些都失去了对后面的影响,需要去掉
                    # 只留下一个更宽的以当前高度为高的矩形
                    curWidth = 1
                    while stack and stack[-1][0] >= height[i][j]:
                        h, w = stack.pop()
                        curWidth += w
                        # 因为将这些更高的高度降至跟当前高度一样
                        # 在这过程中失去的那些全1矩阵数需要减掉
                        cursum -= (h - height[i][j]) * w
                    stack.append([height[i][j], curWidth])
                    cursum += height[i][j]
                    result += cursum
        return result

 提交结果如下:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值