柱状图中最大的矩形

Posted by zhouqian on Sunday, June 26, 2022

力扣 84. 柱状图中最大的矩形

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

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


方案一:构建单调递增栈。因为每遇到右边的高度低于左边, 就表示当前的柱子的高度无法再应用到右边柱子,此时应该计算一次最大矩形面积。

// rect 矩形。
type rect struct {
    width  int
    height int
}

func largestRectangleArea(heights []int) int {
    ans := 0 
    // 构建单调递增栈,高的柱子遇到矮的柱子可以贡献自身高度
    stk := make([]*rect, 0, len(heights))
    // 在柱形图末尾补零,保证触发单调递增栈的出栈逻辑
    heights = append(heights, 0)
    for _, h := range heights {
        acculmatedWidth := 0 
        // 如果栈不空,并且无法构成递增(此时需要出栈栈顶)
        for len(stk) > 0 && stk[len(stk) - 1].height > h {
            // 取栈顶  
            top := stk[len(stk) - 1]
            // 累积宽度(高的柱子贡献了自己的宽度)
            acculmatedWidth += top.width
            // 计算最大值
            ans = max(ans, acculmatedWidth * top.height)
            // 出栈
            stk = stk[:len(stk) - 1]
        }
        // +1 加的是自身的宽度
        acculmatedWidth += 1
        // 入栈当前矩形
        // acculmatedWidth 中包含了如果无法构成单调增而出栈的柱子的宽度
        stk = append(stk, &rect{
            width:  acculmatedWidth,
            height: h,
        })
    }
    return ans
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}
func largestRectangleArea(heights []int) (ans int) {
    // 定义单调递增栈,数组元素为 heights 下标
    stk := make([]int, 0, len(heights))
    // 在数组末尾补上一个题目给定范围的最小值,保证破坏栈内元素单调性
    heights = append(heights, 0)

    for i, height := range heights {
        for len(stk) > 0 {
            // 取栈顶
            top := stk[len(stk) -1]
            // 满足单调性,停止本次内循环
            if heights[top] <= height {
                break
            }

            // 元素出栈
            stk = stk[:len(stk) - 1]
            // 如果此时栈中没有元素,表示 0~index-1 之间的宽度的最高公共长度为 heights[top]
            // 否则就是栈中上一个元素的下标和当前元素下标的差 - 1(宽度) * heights[top]
            if len(stk) > 0 {
                ans = max(ans, (i - stk[len(stk) - 1] - 1) * heights[top])
            } else {
                ans = max(ans, heights[top] * i)
            }
        }
        stk = append(stk, i)
    }
    return
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}
  • 时间复杂度:O(n),因为需要遍历数组中所有元素,虽然遍历途中有入栈出栈的遍历操作(每个元素最多出入一次),但是均摊后时间复杂度还是在 O(n)。
  • 空间复杂度:O(n),因为使用了数个长度不超过 n 的单调栈,所以空间复杂度为 O(n)。