42. 接雨水
思路1:
从左往右,从右往左遍历,分别记录i位置的左右比他高的柱子的最大高度l_max[i]和r_max[i],高度为min(l_max[i], r_max[i]),水容量为min(l_max[i], r_max[i])-height[i]。
class Solution:
def trap(self, height: List[int]) -> int:
if not height:
return 0
# 记录左右侧的最大值
n = len(height)
l_max = [0] * len(height)
r_max = [0] * len(height)
l_max[0] = height[0]
r_max[-1] = height[-1]
# 更新l_max
for i in range(1, n):
l_max[i] = max(height[i], l_max[i-1])
# 更新r_max
for i in range(n-2,-1,-1):
r_max[i] = max(height[i], r_max[i+1])
# 计算容积(从柱子1开始蓄水,并且最后一个只能蓄0,不用管)
result = 0
for i in range(1, n):
result += min(l_max[i], r_max[i]) - height[i]
return result
思路2:
单调栈从栈顶到栈底部从小到大放元素(金字塔),遇到比栈顶大的元素时候,栈顶元素stack[-1]比较小,然后他下面的stack[-2]和当前元素i都比他大,计算stack[-1]的水容量。
< 加入i
= 弹出top,加入i
> 弹出top,更新答案,加入i
class Solution:
def trap(self, height: List[int]) -> int:
# base case
if not height:
return 0
# 高度需要找到左边第一个比他高的右边第一个比他高的。
result = 0
stack = [0]
for i in range(1, len(height)):
# 情况一
if height[i] < height[stack[-1]]:
stack.append(i)
# 相等时候,两个相等的柱子,左边的存不了水,弹出来,更新
elif height[i] == height[stack[-1]]:
stack.pop()
stack.append(i)
else:
# 弹出所有低的柱子
while stack and height[i] > height[stack[-1]]:
mid = stack[-1]
stack.pop()
if stack:
r_h = height[i]
l_h = height[stack[-1]]
h = min(r_h, l_h) - height[mid]
w = i - stack[-1] - 1 # 中间宽度
result += h * w
stack.append(i)
return result
84. 柱状图中最大的矩形
思路:
找到柱子左右侧比他矮的两根柱子left,right,区间内的柱子都比他高,宽度为r-l-1(不包含左右的柱子)
高度是mid;从栈顶到栈底从大到小排列,找到周围比他小的元素。
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
heights.insert(0,0) # 第一个和最后一个柱子可以算面积1*height,而接雨水首位柱子不能接
heights.append(0)
stack = [0]
result = 0 # 最大面积
for i in range(1, len(heights)):
if heights[i] > heights[stack[-1]]:
stack.append(i)
elif heights[i] == heights[stack[-1]]:
stack.pop()
stack.append(i)
else:
while stack and heights[i] < heights[stack[-1]]:
mid = stack[-1]
stack.pop()
if stack:
left = stack[-1]
right = i
width = right - left -1
height = heights[mid]
result = max(result, width * height)
stack.append(i)
return result
简化
def largestRectangleArea(self, heights: List[int]) -> int:
heights.insert(0,0)
heights.append(0)
stack = [0]
result = 0 # 最大面积
for i in range(1, len(heights)):
while stack and heights[i] < heights[stack[-1]]:
mid = stack[-1]
stack.pop()
if stack:
left = stack[-1]
right = i
width = right - left -1
height = heights[mid]
result = max(result, width * height)
stack.append(i)
return result