求最大子矩阵的大小(单调栈)

单调栈

1. 单调栈的结构

背景:给定一个数组,求数组中每一个元素的左边距离其最近的比它小的值,和右边距离其最近的比它小的值。

数组:arr:{3,5,4,2,6}

arr[i]leftright
3null2
534
432
2nullnull
62null

思路:设计一个栈,依次存入的元素大于等于栈顶元素,保持栈中元素从下往上逐渐增大。

  • 如果要存入的元素num大于栈顶,则直接入栈。
  • 如果要存入的元素num等于栈顶,则一起存入栈顶(栈顶中的每一个元素可以用链表实现)。
  • 如果要存入的元素num小于栈顶,则弹出栈顶元素peek,则numpeek的右边距离其最近且小于它的元素。当弹出peek后,此时的栈顶元素peekCurpeek的左边距离其最近且小于它的元素。
  • 当遍历完数组,栈不为空的话,依次弹出栈顶元素peek,此时该peek的右边距离其最近且小于它的元素为null,左边距离其最近且小于它的元素为下一个栈顶元素。

2. 最大拼接的面积

题目:有如下矩形图,求该矩形图中能拼接成矩形的最大面积。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kSLs7rIM-1584967447649)(D:\文档\学习笔记\刷题2\images\单调栈\1584116775791.png)]

思路:用单调栈判断每个矩形左右两边,距离其最近,且比其矮的矩形。

题解

  • 黄色矩形高为5,由于右边棕色矩形比黄色矩形高,所以黄色矩形可以和棕色矩形拼接成高为5,宽为2的矩形。
  • 由于棕色矩形左右两边的矩形都比它低,所以它能拼接成的矩形是他自己。高为6,宽为1。
  • 橙色矩形最低,能拼接所有矩形,最终形成一个高为3,宽为5的矩形。
  • 蓝色矩形也不能和其他矩形拼接,高为7,宽为1。
  • 绿色矩形能和蓝色矩形拼接,形成高为4,宽为2的矩形。

3. 求最大子矩阵的大小

题目:给定一个整型矩阵map, 其中的值只有0 和 1 两种, 求其中全是1 的所有矩形区域中, 最大的矩形区域为1的数量。


1 0 1 1
1 1 1 1
1 1 1 0

其中,最大的矩形区域有6个1,所以返回6 。

思路:把矩阵的每一行看成矩形图。

  • 如第一行[1,0,1,1],把它看成矩形图,由四个矩形组成,高分别为1,0,1,1,宽都为1。求矩形最大拼接面积。
  • 第二行1,1,1,1和第一行[1,0,1,1]组合起来,组成一个矩形图,四个矩形高分别2,1,2,2,宽都为1。求矩形最大拼接面积。
  • 最后一行把整个矩阵看成一个矩形图,注意,四个矩形高分别为3,2,3,0。求矩形最大拼接面积。
  • 得到的矩形最大拼接面积的最大值即为结果。

代码

import java.util.Stack;

class Solution_MaxArea{

    public static int maxAreaMatrix(int[][] arr){
        //判断矩阵是否为空
        if(arr == null || (arr.length == 1 && arr[0].length == 0) || arr.length == 0){
            return 0;                                                                                                    
        }
        int result = Integer.MIN_VALUE;
        int[] rectangle = new int[arr[0].length];
        for(int i = 0; i < arr.length; i++){
            for(int j = 0; j < arr[i].length; j++){
                rectangle[j] = arr[i][j] == 0 ? 0 : rectangle[j] + arr[i][j];
            }
            result = Math.max(maxAreaRectangle(rectangle), result);
        }
        return result;

    }

    public static int maxAreaRectangle(int[] arr){
        if(arr == null || arr.length == 0){
            return 0;
        }
        int len = arr.length;
        Stack<Integer> stack = new Stack<>();
        int res = Integer.MIN_VALUE;
        //哪个元素先弹出,先计算以其代表的矩形的高为最大矩形的高,在遍历到的所有矩形中能合并成的最大矩形 的面积
        for(int i = 0; i < len; i++){
            //注意,是大于等于号。
            while(!stack.isEmpty() && arr[stack.peek()] >= arr[i]){
                int height = arr[stack.pop()];
                int left = stack.isEmpty() ? -1 : stack.peek();
                int right = i;
                int area = height * (right - left - 1);
                res = Math.max(area, res);
            }
            stack.push(i);
        }
        while(!stack.isEmpty()){
            int height = arr[stack.pop()];
            int right = len;
            int left = stack.isEmpty() ? -1 : stack.peek();
            int area = height * (right - left - 1);
            res = Math.max(area, res);
        }
        return res;
    }

    public static void main(String[] args) {
        int[][] arr = {{1,0,1,1},{1,1,1,1},{1,1,1,0}};
        System.out.println(maxAreaMatrix(arr));
    }
}

注意: maxAreaRectangle求最大矩形面积的过程比较特别,对于没有遍历到的矩形,暂时不将其考虑进最大拼接矩形的范围中。比如说矩形2,2,4,6,2,当遍历到i=1时,栈顶元素为1,由于栈顶元素所代表的值为2,与arr[2]相等,所以需要弹出。当前只遍历过一个矩形,所以能形成的最大矩形也就是栈顶元素所代表的那个矩形。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值