【LeetCode】解题84:Largest Rectangle in Histogram

本博客详细介绍了如何解决LeetCode第84题——Largest Rectangle in Histogram,包括两种解题方法:分治法和栈。通过分治法,时间复杂度为O(nlogn);栈的解决方案则利用空间换取时间,遍历过程中维护柱子高度递增,以计算最大面积。最终给出Java实现方案。

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

Problem 84: Largest Rectangle in Histogram [Hard]

Given n non-negative integers representing the histogram’s bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

The largest rectangle is shown in the shaded area, which has area = 10 unit.

Example:

Input: [2,1,5,6,2,3]
Output: 10

来源:LeetCode

解题思路

1. 分治法

在一组不同高度的柱子中求取最大面积,可以通过将其中的最矮柱子作为分割点进行分治,公式为:
m a x a r e a ( 0 , N − 1 ) = max ⁡ { m a x a r e a ( 0 , i n d e x ∗ − 1 ) , N ∗ h e i g h t s [ i n d e x ∗ ] , m a x a r e a ( i n d e x ∗ + 1 , N − 1 ) } max_{area}(0, N-1) = \max\{max_{area}(0, index^*-1), N * heights[index^*], max_{area}(index^*+1, N-1) \} maxarea(0,N1)=max{maxarea(0,index1),Nheights[index],maxarea(index+1,N1)}
其中 i n d e x ∗ index^* index为最矮柱子的下标, m a x a r e a max_{area} maxarea是求取最大面积的函数。

时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)

2. 栈

栈的思想是用空间换取时间,遍历过程中,保证栈内的下标对应的柱子高度值是递增的,这样对于每个不同高度的柱子,都可以在pop()时算出该高度向左向右扩展形成的最大面积。
一个恒定的要素为:(stack[pop-1] ~ stack[pop]) 和 (stack[pop+1] ~ i)下标范围内的柱子高度都大于等于下标为stack[pop]的柱子高度,即:
∀ i n d e x ∈ ( s t [ p o p − 1 ] , s t [ p o p ] ) ∪ ( s t [ p o p ] , i ) , h e i g h t s [ i n d e x ] ≥ h e i g h t s [ s t [ p o p ] ] . \forall index \in (st[pop-1], st[pop]) \cup (st[pop], i), \\ heights[index] \geq heights[st[pop]]. index(st[pop1],st[pop])(st[pop],i),heights[index]heights[st[pop]].
因此,对于下标为 s t [ p o p ] st[pop] st[pop]的柱子,以其高度可扩展的最大面积为 h e i g h t s [ s t [ p o p ] ] ∗ ( i − s t [ p o p − 1 ] − 1 ) heights[st[pop]] * (i - st[pop-1] - 1) heights[st[pop]](ist[pop1]1)
其中 s t [ p o p ] st[pop] st[pop]表示出栈的下标, s t [ p o p − 1 ] st[pop-1] st[pop1]表示出栈元素的前一个下标, i i i表示当前遍历到的下标。

具体过程:

  • 首先需要使用哨兵技巧,在栈中压入值-1,防止之后计算st[pop-1]时会越界。
  • 然后遍历数组,不断压入高度递增的柱子下标i,直到heights[i] < heights[i-1]时停止[1],此时对栈中原有的下标依次进行pop(),计算面积:area = heights[st[pop]] * (i - st[pop-1] -1),更新最大值:max_area = max{max_area, area},直到heights[st[pop]] < heights[i]时停止[2],将当前下标i压入栈。
    注释[1]:这一步中的heights[i] < heights[i-1]时停止压栈,保证了(st[pop], i)下标范围内的柱子都大于等于st[pop]的高度。
    注释[2]:heights[st[pop]] < heights[i]时停止pop(),保证了在i压入栈后,(st[pop*-1], st[pop*])下标范围内的柱子都大于等于st[pop*]的高度。这里的st[pop*]就是刚压入栈的下标i
  • 最后当遍历至数组尾部时,将栈中的下标都以此pop()并计算area。

整个算法入栈和出栈一共遍历了两次数组,时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)

Solution (Java)

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

修改过程

  • for循环中间跳出while时需要检查一下是不是到了数组尾部,是的话要break出来对栈内元素依次pop()。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值