LeetCode Top 100 Liked Questions 85. Maximal Rectangle (Java版; Hard)

welcome to my blog

LeetCode Top 100 Liked Questions 85. Maximal Rectangle (Java版; Hard)

题目描述
Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.

Example:

Input:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
Output: 6
class Solution {
    public int maximalRectangle(char[][] matrix) {
        if(matrix.length==0 || matrix[0].length==0){
            return 0;
        }
        int n = matrix.length, m = matrix[0].length;
        int[] height = new int[m];
        int res=0, cur=0;
        Stack<Integer> s = new Stack<>();
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                height[j] = matrix[i][j]=='1'? height[j]+1 : 0;
            }
            cur = core(height, s);
            res = Math.max(res, cur);
        }
        return res;
    }

    private int core(int[] height, Stack<Integer> s){
        s.clear();
        s.push(-1);
        int res=0, cur;
        //遍历阶段; 每个元素进栈一次   (可能会出栈一次, 或者在清算阶段时出栈一次)
        for(int i=0; i<height.length; i++){
            while(s.peek()!=-1 && height[s.peek()] > height[i]){
                int j = s.pop();
                res = Math.max(res, (i-s.peek()-1)*height[j]);
            }
            s.push(i);
        }
        //清算阶段: 数组中的最后一个元素一定在栈顶
        while(s.peek()!=-1){
            int j = s.pop();
            res = Math.max(res, (height.length - 1 -s.peek())*height[j]);
        }
        return res;
    }
}
第一次做, 使用动态规划, 一层一层处理; 结合最下面的图去理解递推公式; 速度最快, 但是不便于理解, 还要是牢牢掌握单调栈的解法
/*
动态规划版本, 按层计算
对于当前层, 遍历每一列, 对于某一列, 找出该列左右两侧离该列最近且比该列小的柱子
*/
import java.util.Arrays;

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if(matrix==null || matrix.length==0 || matrix[0].length==0)
            return 0;
        //
        int rows = matrix.length;
        int cols = matrix[0].length;
        //对于某一层的某一列, left[j]表示j左边离j最近的并且比matrix[][j]小的柱子
        int[] left = new int[cols];
        Arrays.fill(left, -1);
        //对于某一层的某一列, right[j]表示j右边离j最近的并且比matrix[][j]小的柱子
        int[] right = new int[cols];
        Arrays.fill(right, cols);
        //以某一层的某个点为底, 往上有多少个连续的1, 包括底在内
        int[] heights = new int[cols];
        //newest0表示某一列中, 最靠近j的0的列索引
        int res=0, curr, newest0=-1;
        for(int i=0; i<rows; i++){
            //以当前层的各个点为底, 往上有多少个连续的1
            for(int j=0; j<cols; j++){
                heights[j] = matrix[i][j]=='1' ? heights[j]+1 : 0;
            }            
            //更新left, 找出matrix[][j]左边距离j最近的并且比matrix[][j]小的柱子
            newest0 = -1;
            for(int j=0; j<cols; j++){
                //理解下面的语句要结合图, 否则太抽象了
                //当前位置是1, 对应的left[j]要么不变, 要么更靠近j了
                //更靠近j是因为在靠近j的位置出现了0
                if(matrix[i][j] == '1'){
                    left[j] = Math.max(left[j], newest0);
                }
                //当前位置是0, 不存在比该位置对应值更小的柱子了
                else{
                    left[j] = -1;//这里赋值为-1相当于初始化, 让下一行使用; 不能赋成大于等于0的值
                    newest0 = j;
                }
            }
            //更新right
            newest0 = cols;
            for(int j=cols-1; j>=0; j--){
                if(matrix[i][j]=='1'){
                    right[j] = Math.min(right[j], newest0);
                }
                //当前位置为0, 不存在比该位置对应值更小的柱子了
                else{
                    right[j] = cols;//这里赋成cols相当于初始化, 让下一行使用; 不能赋成小于cols的值
                    newest0 = j;
                }
            }
            //计算面积
            for(int j=0; j<cols; j++){
                curr = (right[j] - left[j] - 1) * heights[j];
                res = Math.max(res, curr);
            }
        }
        return res;
    }
}
第一次做, 多次使用单调栈结构; 栈底到栈顶递增; 注意计算面积时,为什么宽度不能用index求,而必须用s.peek()求; char与ascii与整数的细节, 看代码
/*
使用单调栈: 栈底到栈顶递增
和84题很像, 使用84单调栈的处理方式
*/
import java.util.Stack;

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if(matrix==null || matrix.length==0 || matrix[0].length==0)
            return 0;
        //
        int[] heights = new int[matrix[0].length];
        int res = 0, curr;
        Stack<Integer> s = new Stack<>();
        for(int i=0; i<matrix.length; i++){
            for(int j=0; j<matrix[0].length; j++){
                //统计以matrix[i][j]往上有多少个连续的1, 包括matrix[i][j]自己
                //ascii: 48是'0', 49是'1'
                heights[j] = matrix[i][j]==49? heights[j]+1 : 0;
                /*
                这里也可以写成
                heights[j] = matrix[i][j]=='1' ? heights[j]+1 : 0;
                */
            }
            curr = monotonousStack(heights, s);
            res = Math.max(res, curr);
        }
        return res;
    }
    public int monotonousStack(int[] heights, Stack<Integer> s){
        //由于矩阵的每一行用的都是同一个栈, 所以使用前先清空一下栈
        s.clear();
        
        //单调栈: 栈底到栈顶递增
        //栈中存索引; 压入参考值-1
        s.push(-1);
        //遍历阶段
        int res=0, curr, index;
        for(int i=0; i<heights.length; i++){
            while(s.peek()!=-1 && heights[s.peek()] > heights[i]){
                //弹出栈顶元素
                index = s.pop();
                //计算面积
                //计算宽度时必须用s.peek(),不能用index! 因为从index处也许能够向左扩展(和左神讲的思路一致); 想不明白用用[3,1,3,2,2]进行debug
                curr = heights[index] * (i - s.peek() - 1);
                //
                res = Math.max(res, curr);
            }
            s.push(i);
        }
        //清算阶段
        while(s.peek()!=-1){
            //heights[index]是{index,index+1,...,heights.length-1}范围上值最小的
            index = s.pop();
            //计算面积
            curr = heights[index] * (heights.length-1 - s.peek());
            //
            res = Math.max(res, curr);
        }
        return res;
    }
}
按层来看, 这道题就是84题的加强版

84题图

85题图, 图片来源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值