剑指offer 专项突破版 39、直方图最大矩形面积

题目链接

思路

可以用暴力、分治、单调栈解决,我选了单调栈的做法~

  • 我们知道在计算某一个柱子围城的最大矩形面积时,目的是要寻找他左右两边第一个比他低的柱子。也就是说,我们在扫描到某一个柱子时要从后向前,挨个通知比他低的柱子,因为当前的柱子就是他前面相邻的所有比他低的柱子的右边界!
  • 这种扫描到某个地方先保存,等到某个时机成熟时从后往前通知自然要用栈来实现
  • 因此可以用栈来模拟这个过程(为了计算面积,存的是索引)
    • 在扫描到某个柱子时,如果它比栈顶元素对应的height大,那就入栈
    • 如果他比栈顶元素对应的height小,那就把栈顶元素一直pop,直到他比栈顶元素大,在这个过程中要同时计算矩形面积
    • 具体的计算方法为,我们假设栈顶元素为i,当前元素为j,栈顶下方元素为k,此时需要计算的是以栈顶的柱子围成的最大矩形。我们知道当前的索引是栈顶矩形的右边界(因为现在的柱子肯定比栈顶的柱子小),那么根据之前入栈的条件,栈顶下方的元素一定是左边界,具体的计算方法为(j-k)*heights[i]
    • 当栈中所有比当前元素对应的height大的索引弹出后,还要把当前元素push进去,因为我们只有在pop的过程中才计算了某个柱子可以围成的最大矩形
    • 当柱子遍历结束后,栈中可能还有元素,这是当然是有可能发生的~因为会看前面的过程,只有当前元素比栈顶元素对应的height小的时候才会出栈,那么如果某个柱子比后面所有的柱子都要低,他自然不会出栈,那么此时应该处理这些在栈中的元素。这些元素的右边界是最右边,那么此时的j应该是heights.length,i自然还是栈顶元素
    • 到此我们还漏了最至关重要的一步,那就是左侧的边界!我们说某个柱子围成的最大矩形,两侧都应该达到第一个比他低的柱子,假如右侧没有比他低的,那他的右边界就是heights.length,而左侧,自然就是-1,为了保证判断的连续性,我们最开始要把-1加入到栈中,这样在得到左边界时我们依旧可以通过栈顶下方的元素j来获得到~
class Solution {
    public int largestRectangleArea(int[] heights) {

        int max = Integer.MIN_VALUE;
        Stack<Integer> s = new Stack<>();
        s.push(-1);

        for (int i = 0; i < heights.length; i++) {

            while (-1 != s.peek() && heights[i] < heights[s.peek()]) {
                int index = s.pop();
                max = Math.max(max, (i - s.peek() - 1) * heights[index]);
            }
            s.push(i);
        }

        while (-1 != s.peek()) {
            int index = s.pop();
            max = Math.max(max, (heights.length - s.peek() - 1) * heights[index]);
        }

        return max;
    }
}
Go代码
func largestRectangleArea(heights []int) (result int) {
	var stack []int

	for i, height := range heights {
		for len(stack) != 0 && heights[stack[len(stack)-1]] >= height {
			rectangleHeight := heights[stack[len(stack)-1]]
			stack = stack[0 : len(stack)-1]
			var left int
			if len(stack) == 0 {
				left = -1
			} else {
				left = stack[len(stack)-1]
			}
			result = max(result, rectangleHeight*(i-left-1))
		}
		stack = append(stack, i)
	}

	right := len(heights)
	for len(stack) != 0 {
		height := heights[stack[len(stack)-1]]
		stack = stack[0 : len(stack)-1]
		var left int
		if len(stack) == 0 {
			left = -1
		} else {
			left = stack[len(stack)-1]
		}
		result = max(result, height*(right-left-1))
	}

	return
}

func max(m, n int) int {
	if m >= n {
		return m
	}
	return n
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值