LeetCode刷题笔记 84

题目:柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
在这里插入图片描述
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。

在这里插入图片描述
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10

答案:
1.暴力法
对每个子区间进行最大矩形面积求解,更新最大面积

class Solution {
    public int largestRectangleArea(int[] heights) {
        int maxArea = 0;
        int minVal;
        for(int i = 0; i < heights.length; i++) {
            minVal = heights[i];
            for(int j = i; j < heights.length; j++) {
                if(heights[j] < minVal) minVal = heights[j];
                maxArea = Math.max(maxArea,minVal*(j-i+1));
            }
        }
        return maxArea;
    }
}

时间复杂度:O(n2)。 需要枚举所有可能的柱子对。
空间复杂度:O(1) 。不需要额外的空间。

2.分治法
参考链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/zhu-zhuang-tu-zhong-zui-da-de-ju-xing-by-leetcode/
最大面积矩形存在于以下几种情况:
(1)确定了最矮柱子以后,矩形的宽尽可能往两边延伸。
(2)在最矮柱子左边的最大面积矩形(子问题)。
(3)在最矮柱子右边的最大面积矩形(子问题)。
eg:[6, 4, 5, 2, 4, 3, 9]
这里最矮柱子高度为 2 。以 2 为高的最大子矩阵面积是 2x7=14 。现在,我们考虑上面提到的第二种和第三种情况。我们对高度为 2 柱子的左边和右边采用同样的过程。在 2 的左边, 4 是最小的,形成区域为 4x3=12 。将左边区域再继续分,矩形的面积分别为 6x1=6 和 5x1=5 。同样的,我们可以求出右边区域的面积为 3x3=9, 4x1=4 和 9x1=9 。因此,我们得到最大面积是 14 。具体过程可参考下图:
在这里插入图片描述

class Solution {
    public int largestRectangleArea(int[] heights) {
        return calculateArea(heights, 0, heights.length - 1);
    }
    public int calculateArea(int[] heights, int start, int end) {
        if (start > end)
            return 0;
        int minindex = start;
        for (int i = start; i <= end; i++)
            if (heights[minindex] > heights[i])
                minindex = i;
        return Math.max(heights[minindex] * (end - start + 1), Math.max(calculateArea(heights, start, minindex - 1), calculateArea(heights, minindex + 1, end)));
    }
}

时间复杂度:
平均开销:O(nlogn)
最坏情况:O(n2)。如果数组中的数字是有序的,分治算法将没有任何优化效果。
空间复杂度:O(n)。最坏情况下递归需要 O(n) 的空间。

3.单调栈(想法很重要)
我们维护一个栈。一开始,我们把 -1 放进栈的顶部来表示开始。初始化时,按照从左到右的顺序,我们不断将柱子的序号放进栈中,直到遇到相邻柱子呈下降关系,也就是 a[i-1] > a[i] 。将栈中的序号弹出,直到遇到 stack[j] 满足a[stack[j]]≤a[i](保持单调递增的关系)。每次弹出stack[top] 时,记当前元素在原数组中的下标为 i ,当前弹出元素为高的最大矩形面积为:
(i−stack[top−1]−1)×a[stack[top]].

public class Solution {
    public int largestRectangleArea(int[] heights) {
        Stack < Integer > stack = new Stack < > ();
        stack.push(-1);
        int maxarea = 0;
        for (int i = 0; i < heights.length; ++i) {
            while (stack.peek() != -1 && heights[stack.peek()] >= heights[i])
                maxarea = Math.max(maxarea, heights[stack.pop()] * (i - stack.peek() - 1));
            stack.push(i);
        }
        while (stack.peek() != -1)
            maxarea = Math.max(maxarea, heights[stack.pop()] * (heights.length - stack.peek() -1));
        return maxarea;
    }
}

时间复杂度:O(n)。 n 个数字每个会被压栈弹栈各一次。
空间复杂度:O(n)。用来存放栈中元素。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值