Leetcode使用单调栈解决柱状图面积问题

今天刚做了两道Leetcode上难度为Hard的难题,使用到了单调栈的思想,这里将思路总结一下,便于后续复习。

这两道题分别是:

Leetcode 84. 柱状图中最大的矩形

Leetcode 85. 最大矩形

1.题目描述

1.1 Leetcode84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例1:

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

1.2 Leetcode 85. 最大矩形

给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例1:

 输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:6
解释:最大矩形如上图所示。

2.思路分析

对于84题,可以计算每一个位置 i 处可以组成的矩形面积,遍历求最大值即可。

为了计算矩形面积,需要知道柱子的高和宽,高已经知道了,即heights[ i ],而宽可以通过计算 i 左右两边的边界位置来计算。左右两边边界的位置表示为:以 i 为中心,向左向右遍历到的第一个小于heights[ i ]的位置,可以通过单调栈快速计算。

对于85题,可以将图片逆时针旋转90°,看成是以列为单位一列一列的柱状图,和84题同理,计算每一列柱状图的最大矩形面积,然后求全局最大值即可。

进一步,要想计算柱状图面积,就需要知道柱子的高和宽:

  • 计算高:用二维数组left[ i ][ j ]表示(i, j)位置左侧格子中1的个数(包括(i, j))。
  • 计算宽:用单调栈计算左右边界,同84题。

3.解答

3.1 Leetcode84. 柱状图中最大的矩形

class Solution {
    //单调栈

    public int largestRectangleArea(int[] heights) {
        int n = heights.length;

        //分别存储当前位置左侧和右侧最近的边界(小于当前值的位置)
        int[] left = new int[n];
        int[] right = new int[n];

        //使用单调栈查找每个位置的左右边界
        Deque<Integer> stack = new ArrayDeque<>();

        //从左向右遍历
        for(int i = 0; i < n; i++){
            while(!stack.isEmpty() && heights[i] <= heights[stack.peek()]){
                stack.pop();
            }
            left[i] = stack.isEmpty() ? -1 : stack.peek();
            stack.push(i);
        }

        stack.clear();

        //从右向左遍历
        for(int j = n - 1; j >= 0; j--){
            while(!stack.isEmpty() && heights[j] <= heights[stack.peek()]){
                stack.pop();
            }
            right[j] = stack.isEmpty() ? n : stack.peek();
            stack.push(j);
        }

        //遍历计算以当前位置为中心的矩形面积,找出最大值
        int res = 0;
        for(int k = 0; k < n; k++){
            res = Math.max(res, (right[k] - left[k] - 1) * heights[k]);
        }

        return res;
    }
}

复杂度分析

  • 时间复杂度:O(N)。

  • 空间复杂度:O(N)。

 3.2 Leetcode 85. 最大矩形

class Solution {
    //单调栈

    public int maximalRectangle(char[][] matrix) {
        int m = matrix.length;
        if(m == 0){
            return 0;
        }
        int n = matrix[0].length;

        //存储位置(i,j)左边的格子中1的个数
        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 ? 1 : left[i][j - 1] + 1);
                }
            }
        }

        //以列为单位进行遍历计算每一个矩形的面积
        int res = 0;
        for(int j = 0; j < n; j++){
            //使用单调栈计算每一行矩形的长度(侧着看就是柱子的高度)
            Deque<Integer> stack = new ArrayDeque<>();

            //从上到下遍历
            int[] up = new int[m];
            for(int i = 0; i < m; i++){
                while(!stack.isEmpty() && left[i][j] <= left[stack.peek()][j]){
                    stack.pop();
                }
                up[i] = stack.isEmpty() ? -1 : stack.peek();
                stack.push(i);
            }

            stack.clear();

            //从下到上
            int[] down = new int[m];
            for(int i = m - 1; i >= 0; i--){
                while(!stack.isEmpty() && left[i][j] <= left[stack.peek()][j]){
                    stack.pop();
                }
                down[i] = stack.isEmpty() ? m : stack.peek();
                stack.push(i);
            }

            //遍历计算每个矩形的面积
            for(int k = 0; k < m; k++){
                int high = down[k] - up[k] - 1;
                int width = left[k][j];
                res = Math.max(res, high * width);
            }
        }

        return res;
    }
}

复杂度分析

  • 时间复杂度:O(mn)。

  • 空间复杂度:O(mn)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值