算法学习——剑指 Offer II 040. 矩阵中最大的矩形(Java实现)

Posted stormzhuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法学习——剑指 Offer II 040. 矩阵中最大的矩形(Java实现)相关的知识,希望对你有一定的参考价值。

1. 题意

这是LeetCode上的 [040,矩阵中最大的矩形],难度为 [困难]

2. 思路分析

这道题跟上一题一样还是求最大矩形的面积,所以求最大矩形的面积可以参考直方图的最大矩形面积,那么这道题的关键在于从矩阵中找出所有的直方图,然后再从所以直方图中找到最大的矩形

直方图是由排列在同一基线上的相邻柱子组成的的图形,题意要求矩形中只包含数字1,那么可以把矩阵中上下相邻的值为1的格子看成是一个柱子,因此可以把矩阵中的每一行看作基线,这样矩阵有多少行就有多少个直方图,直方图最大的矩形即为解的答案

需要注意的是每一行组合而成的直方图的每个柱子的高度实在下面两种情况得出的

  • 若柱子的高度为1,则它的实际高度是在上一行相同列的柱子高度加1得到的
  • 若柱子的高度为0,则它的实际高度为0

例如如下图所示的矩阵,如果分别以矩阵的每行为基线,就可以得到4个由数字1组成的直方图

以矩阵第一行为基线的直方图,如下所示

以矩阵第二行为基线的直方图,柱子的高度是在第一行高度的基础上累加起来的,例如第二行的第三列的值1,而它上一行的同一列的柱子高度为1,因此它的柱子高度为1+1=2,如下所示


以矩阵第三行为基线的直方图,柱子的高度是在第二行高的基础累加的,例如第三行的第三列的值为1,而它上一行的相同列的高度为2,因此它的高度为2 + 1 = 3

它的最大矩形也是整个矩阵中只包含1的最大矩形,如阴影部分显示

以矩形第4行为基线的直方图,柱子的高度计算跟前面是一样的,如下所示

2.1 代码实现

class Solution 
    public int maximalRectangle(String[] matrix) 
        // 若数组长度为0,则矩阵是空的,返回0
        if (matrix.length == 0) 
            return 0;
        
        // 创建一个柱子数组,存放直方图每个柱子的高度,长度为字符串的长度
        int[] heights = new int[matrix[0].length()];
        // 记录每个直方图最大的矩形面积
        int maxArea = 0;
        // 嵌套遍历,获取数组每个字符串的每个字符
        for (String rows : matrix) 
            for (int i = 0; i < rows.length(); i++) 
                // 若当前字符为0,则柱子的高度为0
                if (rows.charAt(i) == '0') 
                    heights[i] = 0;
                 else 
                    // 否则字符为1,则柱子的高度是在上一行同一列的柱子的高度累加的
                    heights[i]++;
                
            
            maxArea = Math.max(maxArea, largestRectangleArea(heights));
        
        return maxArea;
    

     public int largestRectangleArea(int[] heights) 
        // 创建一个栈存放递增的柱子
        Deque<Integer> stack = new LinkedList<>();
        // 压入一个-1的下标,用来处理栈顶左侧没有柱子的情况
        stack.push(-1);
        // 记录最大矩形面积
        int maxArea = 0;
        // 遍历数组
        for (int i = 0; i < heights.length; i++) 
            // 若栈有柱子元素(-1是想象虚拟的柱子),并且栈顶元素大于当前遍历的柱子高度执行逻辑
            while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) 
                // 弹出栈顶元素,计算栈顶元素的最大矩形面积
                int height = heights[stack.pop()];
                int width = i - stack.peek() - 1;
                maxArea = Math.max(height * width, maxArea);
            
            stack.push(i);
        
        // 遍历完数组后,栈可能还有柱子的执行逻辑
        while (stack.peek() != -1) 
            int height = heights[stack.pop()];
            int width = heights.length - stack.peek() - 1;
            maxArea = Math.max(height * width, maxArea);
        
        return maxArea;
    

2.2 复杂度分析

假设输入的矩阵大小为m x n,则该矩阵可以转换成m个直方图

时间复杂度

采用单调栈法求直方图的最大面积的时间复杂度为O(n),由于由m个直方图,故总的时间复杂度为O(m x n)

空间复杂度

同样地,单调栈法的空间复杂度为O(n),还需要一个长度为n的数组height,故总的空间复杂度为O(n)

以上是关于算法学习——剑指 Offer II 040. 矩阵中最大的矩形(Java实现)的主要内容,如果未能解决你的问题,请参考以下文章