剑指 Offer II 040. 矩阵中最大的矩形(85. 最大矩形)

题目:

思路:

【0】思路源于模拟圆柱的思想

以一下数据为例:
[
    {1,0,0,0,1,1,0,0,1},
    {1,0,0,0,0,1,0,0,1},
    {1,0,0,0,1,1,0,0,1},
    {1,0,1,1,1,1,0,0,1},
    {1,1,0,1,1,1,0,0,1}
]

首先计算出矩阵的每个元素的左边连续 1 的数量
如最后一行,{1,1,0,1,1,1,0,0,1}
得
[1,2,0,1,2,3,0,0,1]

那么当如果处于下标4的时候值为2
如果往上,上面的位置是3,所以其实是可以取得2*2的矩阵,但是去不了3*3,因为矩阵取决于最小的限制。
再往上便是1,所以矩阵为1*3

其实这里如果从后面往前面遍历会更好,如果取得了最大值,且当前的底边大小*往上的边界值都不如最大值,其实该位置就可以直接跳过了,减少遍历的情况(类似于剪枝)

 

【1】使用柱状图的优化暴力方法

【2】单调栈的方法

代码展示:

优化的方法:

//时间2 ms击败99.34%
//内存43.6 MB击败99.85%
class Solution {
    public int maximalRectangle(char[][] matrix) {
        int[] heights = new int[matrix[0].length];
        int max = 0;
        for (int i = 0; i < matrix.length; i++) {
            updateHeights(heights, matrix[i]);

            max = Math.max(max, largestRectangleArea(heights));
        }

        return max;
    }

    private int largestRectangleArea(int[] heights) {
        int len = heights.length;
        int max = 0;
        int[] stack =  new int[len];
        int k = -1;
        for (int r = 0; r < len; r++) {
            while (k != -1 && heights[stack[k]] > heights[r]) {
                int low = stack[k--];
                int l = k == -1 ? -1 : stack[k];
                max = Math.max(max, (r - 1 - l) * heights[low]);
            }
            stack[++k] = r;
        }
        while (k != -1) {
            int low = stack[k--];
            int l = k == -1 ? -1 : stack[k];
            max = Math.max(max, (len - 1 - l) * heights[low]);
        }

        return max;
    }

    public void updateHeights(int[] heights, char[] cells) {
        for (int j = 0; j < heights.length; j++) {
            heights[j] = cells[j] == '0' ? 0 : heights[j] + 1;
        }
    }
}

 

使用柱状图的优化暴力方法:

//时间13 ms击败52.85%
//内存39.7 MB击败96.70%
class Solution {
    public int maximalRectangle(String[] matrix) {
        int m = matrix.length;
        if (m == 0) {
            return 0;
        }
        int n = matrix[0].length();
        int[][] left = new int[m][n];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i].charAt(j) == '1') {
                    left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;
                }
            }
        }

        int ret = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i].charAt(j) == '0') {
                    continue;
                }
                int width = left[i][j];
                int area = width;
                for (int k = i - 1; k >= 0; k--) {
                    width = Math.min(width, left[k][j]);
                    area = Math.max(area, (i - k + 1) * width);
                }
                ret = Math.max(ret, area);
            }
        }
        return ret;
    }
}

//时间17 ms击败45.72%
//内存43.4 MB击败99.85%
class Solution {
    public int maximalRectangle(char[][] matrix) {
        int m = matrix.length;
        if (m == 0) {
            return 0;
        }
        int n = matrix[0].length;
        int[][] left = new int[m][n];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '1') {
                    left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;
                }
            }
        }

        int ret = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '0') {
                    continue;
                }
                int width = left[i][j];
                int area = width;
                for (int k = i - 1; k >= 0; k--) {
                    width = Math.min(width, left[k][j]);
                    area = Math.max(area, (i - k + 1) * width);
                }
                ret = Math.max(ret, area);
            }
        }
        return ret;
    }
}

 

单调栈的方法:

//时间13 ms击败52.85%
//内存42.4 MB击败5.1%
class Solution {
    public int maximalRectangle(String[] matrix) {
        int m = matrix.length;
        if (m == 0) {
            return 0;
        }
        int n = matrix[0].length();
        int[][] left = new int[m][n];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i].charAt(j) == '1') {
                    left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;
                }
            }
        }

        int ret = 0;
        for (int j = 0; j < n; j++) { // 对于每一列,使用基于柱状图的方法
            int[] up = new int[m];
            int[] down = new int[m];

            Deque<Integer> stack = new ArrayDeque<Integer>();
            for (int i = 0; i < m; i++) {
                while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {
                    stack.pop();
                }
                up[i] = stack.isEmpty() ? -1 : stack.peek();
                stack.push(i);
            }
            stack.clear();
            for (int i = m - 1; i >= 0; i--) {
                while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {
                    stack.pop();
                }
                down[i] = stack.isEmpty() ? m : stack.peek();
                stack.push(i);
            }

            for (int i = 0; i < m; i++) {
                int height = down[i] - up[i] - 1;
                int area = height * left[i][j];
                ret = Math.max(ret, area);
            }
        }
        return ret;
    }
}


//时间20 ms击败33.54%
//内存43.9 MB击败99.71%
class Solution {
    public int maximalRectangle(char[][] matrix) {
        int m = matrix.length;
        if (m == 0) {
            return 0;
        }
        int n = matrix[0].length;
        int[][] left = new int[m][n];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '1') {
                    left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;
                }
            }
        }

        int ret = 0;
        for (int j = 0; j < n; j++) { // 对于每一列,使用基于柱状图的方法
            int[] up = new int[m];
            int[] down = new int[m];

            Deque<Integer> stack = new LinkedList<Integer>();
            for (int i = 0; i < m; i++) {
                while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {
                    stack.pop();
                }
                up[i] = stack.isEmpty() ? -1 : stack.peek();
                stack.push(i);
            }
            stack.clear();
            for (int i = m - 1; i >= 0; i--) {
                while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {
                    stack.pop();
                }
                down[i] = stack.isEmpty() ? m : stack.peek();
                stack.push(i);
            }

            for (int i = 0; i < m; i++) {
                int height = down[i] - up[i] - 1;
                int area = height * left[i][j];
                ret = Math.max(ret, area);
            }
        }
        return ret;
    }
}

 

posted @ 2023-04-28 12:29  忧愁的chafry  阅读(43)  评论(0编辑  收藏  举报