leetcode84柱状图中最大的矩形

题目

leetcode84柱状图中最大的矩形_第1张图片
leetcode84柱状图中最大的矩形_第2张图片

思路:暴力法O(n^2)超时,考虑单调栈。

①从左向右遍历,对于每个高度的柱子,找到其左边第一个比它小的柱子i
②从右向左遍历,对于每个高度的柱子,找到其右边第一个比它小的柱子j
如此以来,对于每个柱子,得到的就是该柱子能向两边扩展的最远距离

该过程用单调栈实现,具体实现如下:

1、从左向右遍历

[2,1,5,6,2,3]

stack栈中存放的是柱子下标,维持栈元素单调递增

将得到的第一个比当前柱子小的柱子存入left列表中

特殊情况下,比如对于第一个元素2,前面没有比其更小的数了,对于这样的数,
统一设置一个“哨兵”,即当前结果为-1

注:先更新left元素值,再插入当前位置的下标

具体步骤为:
stack = []
left = [-1]*n
①2(0)1(1)1(1)<2(0)1(1) 5(2)   ∴left[2]=11(1) 5(2) 6(3)   ∴left[3]=21(1) 2(4)   ∴left[4]=11(1) 2(4) 3(5)   ∴left[5]=4

具体实现代码如下:
stack = []
left = [-1]*n
for i in range(n):
	while stack and heights[stack[-1]] >= heights[i]:
		stack.pop()
	if stack:
		left[i] = stack[-1]
	stack.append(i)

2、从右向左遍历

[3,2,6,5,1,2]
设置右边的一个哨兵,为数组长度6
right=[6]*n

①2(5)1(4)1(4) 5(3)   ∴right[3]=41(4) 5(3) 6(2)   ∴right[2]=31(4) 2(1)   ∴right[1]=41(4) 2(1) 3(0)   ∴right[0]=1

具体实现代码同上,只是初始化和遍历方式有所改变:
stack = []
right = [n]*n
for i in range(n-1, -1, -1):
	while stack and heights[stack[-1]] >= heights[i]:
		stack.pop()
	if stack:
		right[i] = stack[-1]
	stack.append(i)

所以本题的代码为:

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        if not heights: return 0
        n = len(heights)
        if n == 1: return heights[0]
        stack, left = [], [-1]*n
        for i in range(n):
            while stack and heights[stack[-1]] >= heights[i]:
                stack.pop()
            if stack:
                left[i] = stack[-1]
            stack.append(i)
        stack, right = [], [n]*n
        for i in range(n-1, -1, -1):
            while stack and heights[stack[-1]] >= heights[i]:
                stack.pop()
            if stack:
                right[i] = stack[-1]
            stack.append(i)
        res = 0
        for i in range(n):
            res = max(res, heights[i]*(right[i]-left[i]-1))
        return res

但是!!!还可以继续优化,现在的方法是对数组遍历两次,优化之后对数组遍历一次即可。

回顾之前从左向右遍历的弹栈的操作,为什么要将栈顶元素弹出去?正是因为当前遍历的数比栈顶元素要小,因此,可以得出,弹出去的栈顶元素其右边最小的就是当前遍历的数,不仅如此,如果需要连续多次弹栈,则因为栈中的元素是单调递增的,所以弹出去的数其右边最小的柱子都是当前遍历的数

优化代码如下:

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        if not heights: return 0
        n = len(heights)
        if n == 1: return heights[0]
        stack, left, right = [], [-1]*n, [n]*n
        for i in range(n):
            while stack and heights[stack[-1]] >= heights[i]:
                right[stack[-1]]=i
                stack.pop()
            if stack:
                left[i] = stack[-1]
            stack.append(i)
        res = 0
        for i in range(n):
            res = max(res, heights[i]*(right[i]-left[i]-1))
        return res

你可能感兴趣的:(leetcode)