LeetCode-84

博客介绍了如何解决计算直方图中最大矩形面积的问题,首先从暴力解法入手,分析了两种O(n^2)和O(n^3)的时间复杂度解法,然后通过引入单调栈优化算法,将时间复杂度降低到O(n),详细解释了单调栈确定左右边界的原理,并给出了相应的Java代码实现。最终,对比了暴力解法和单调栈法的运行效率,强调了优化算法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看了官方的视频后,才得知该题是一道很经典的题目了。官方推荐首先采用暴力解法,然后再优化为单调栈。

暴力解法

要求矩形的面积,首先要知道长和宽(这道题由于是在直方图中,所以下面称为宽和高),所以有两种办法,第一种是固定宽,然后找高;第二种是固定高,然后找宽。如果采用固定宽,那么会导致O( n 3 n^3 n3)的复杂度。如果采用固定高,会有O( n 2 n^2 n2)的复杂度。官方说通过Java提交暴力解法也可以通过测试,而且暴力解法有助于了解一些细节。
具体思路就是,遍历每一个元素,当前元素为高,然后依次往两边遍历,直到两边的高度都比当前高度低或者是到达边界。

class Solution1 {
   public int largestRectangleArea(int[] heights) {
       int aws = 0, tmp;
       int p, q;
       for (int i = 0; i < heights.length; i++) {
           p = q = i;
           while (p > 0 && heights[p - 1] >= heights[i]) {
               --p;
           }
           while (q < heights.length - 1 && heights[q + 1] >= heights[i]) {
               ++q;
           }
           if ((tmp = (q - p + 1) * heights[i]) > aws) {
               aws = tmp;
           }
       }
       return aws;
   }
}

单调栈法

暴力解法中对于每个元素,都要确定其左右边界,假如元素是递增关系,那么对于这些元素的右边界的可以一次求出来,即找到右边第一个比当前值小的元素。所以,如果当前元素依次递增,大可不必立马求出其右边界,可以将其放入栈中,然后出栈时,即可确定右边界。

上面讲了如何确定右边界,那么该如何确定左边界,刚开始我误认为左边界就是当前元素,因为元素是递增的。 但是只能确保当前元素到右边界(不包括)这一段内是递增的。对于左边界,无法确定。最后想到可以通过次栈顶+1来找到左边界。

代码实现的总体思路也比较简单,如果当前元素大于等于当前元素,则入栈,否则出栈。但是有些细节比较恼人。

  • 栈空时,不能出栈。(虽然这是一句废话)
  • 所有元素递增,则最后需要强制出栈。
  • 如果栈中仅有一个元素,那么左边界为0。

代码如下:

class Solution {
    public int largestRectangleArea(int[] heights) {
        int aws = 0, i = 0, tmp;
        Deque<Integer> stack = new ArrayDeque<>(heights.length);
        while (i <= heights.length) {
            if ((i == heights.length ? -1 : heights[i]) < (stack.isEmpty() ? -1 : heights[stack.getLast()])) { // 出栈
                if((tmp = heights[stack.pollLast()] * (i - (stack.isEmpty() ? 0 : stack.getLast() + 1))) > aws) {
                    aws = tmp;
                }
            } else { // 入栈
                stack.addLast(i++);
            }
        }
        return aws;
    }
}

暴力解法占用了1188ms,而单调栈法仅用了16ms。
上述代码是针对于依次递增的情况,其实也可以采用依次递减的方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值