单调栈练习(三)— 最大矩形

题目
同样是LeetCode原题:题目链接
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

在这里插入图片描述

暴力解
先来看一下暴力解的时间复杂度。
假如一个N * N的大矩阵,想要枚举出来所有的子矩阵时间复杂度是多少? O ( N 4 ) O(N^4) O(N4)
是这样算的:
在N * N中随便点一个点A的可能性是 O ( N 2 ) O(N^2) O(N2)种,再随便点一个点B,同样也是 O ( N 2 ) O(N^2) O(N2)种可能性。
这两个点,一个在左上角,一个在右下角,就能够构成一个子矩阵,整体的时间复杂度是 O ( N 4 ) O(N^4) O(N4)

就算是点的点重复,那也只是重复了一次,不影响结果。所以枚举所有子矩阵的整体时间复杂度为 O ( N 4 ) O(N^4) O(N4)

整个暴力解的思路就是,先用4个for循环枚举出来所有的子矩阵(时间复杂度为 O ( N 4 ) O(N^4) O(N4)),再验证所有的子矩阵中的值是否都是1,并求出最大值。时间复杂度 O ( N 2 ) O(N^2) O(N2)。整个暴力解的时间复杂度为 O ( N 6 ) O(N^6) O(N6)

单调栈
单调栈用到了一个技巧:压缩数组 。优化下后的整体时间复杂度是 O ( N 2 ) O(N^2) O(N2)

数组压缩的技巧可以将给定的二维数组构建成自己想要的柱状图,并利用单调栈,弹出当前栈顶元素,以当前栈顶元素的值为子矩阵中统一的高,并且找到左右区间最近且小的值作为边界,根据中间部分符合条件的值求出其最大面积,这部分具体可以看上一篇文章,可以说是一毛一样柱状图中最大的矩形

在遍历给定的二维数组并构建压缩数组的过程中,如果 arr[i] [j] 和 arr[i + 1] [j] 位置的值都为1,则压缩完的数组中arr[j] 位置的值应该进行累加为2,如果中间断掉为0,则构建出来的柱状图对应的位置为0。

这样就能求出以二维数组中的每一行为底、每一行的每一个为子矩阵的高的每一个子矩阵的面积是多少。
遍历完整个二维数组后,最大面积也就求出来了。

代码
二维数组每遍历完一行,就求一次以当前行为底的所有子矩阵的最大面积。
maxRecFromBottom和上一篇帖子的解题思路一样柱状图中最大的矩形

 public static int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix[0].length == 0){
            return 0;
        }
        int N = matrix[0].length;
        int M = matrix.length;
        int[] helpArr = new int[N];
        Integer max = Integer.MIN_VALUE;
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                helpArr[j] = matrix[i][j] == '0' ? 0 : helpArr[j] + 1;
            }
              max = Math.max(max,maxRecFromBottom(helpArr));
        }

        return max;
    }

    public static int maxRecFromBottom(int[] height) {
        Stack<Integer> stack = new Stack<>();
        Integer max = Integer.MIN_VALUE;
        for (int i = 0; i < height.length; i++) {
            while (!stack.isEmpty() && height[i] < height[stack.peek()]) {
                Integer cur = stack.pop();
                Integer leftMin = stack.isEmpty() ? -1 : stack.peek();
                max = Math.max(max,(i - leftMin - 1) * height[cur]);
            }
            stack.push(i);
        }
        while (!stack.isEmpty()){
            Integer cur = stack.pop();
            Integer leftMin = stack.isEmpty() ? -1 : stack.peek();
            max = Math.max(max,(height.length - leftMin - 1) * height[cur]);
        }
        return max;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值