打卡Day49
1. 42. 接雨水
暴力解法(会超时):
按照列计算,宽度为1,把每一列的雨水宽度求出来就行。每一列雨水的高度,取决于该列最侧最高的柱子和右侧最高的柱子中最矮的柱子的高度。要注意第一个柱子和最后一个柱子不接雨水。
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
res = 0
for i in range(len(height)):
if i == 0 or i == len(height)-1:
continue
lheight = height[i-1]
rheight = height[i+1]
for j in range(i-1):
if height[j] > lheight:
lheight = height[j]
for j in range(i+2,len(height)):
if height[j] > rheight:
rheight = height[j]
res1 = min(lheight,rheight) - height[i]
if res1 > 0:
res += res1
return res
双指针:
暴力解法中计算左右侧最高柱子的高度是有重复的,可以使用两个数组来记录每个位置左右边的最高高度。当前位置,左边的最高高度是前一个位置的左边最高高度和本高度的最大值。同理右边也是。
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
lheight = [0] * len(height)
rheight = [0] * len(height)
lheight[0] = height[0]
for i in range(1,len(height)):
lheight[i] = max(height[i],lheight[i-1])
rheight[-1] = height[-1]
for i in range(len(height)-2,-1,-1):
rheight[i] = max(rheight[i+1],height[i])
res = 0
for i in range(len(height)):
summ = min(lheight[i],rheight[i]) - height[i]
res += summ
return res
单调栈:
这道题需要寻找一个元素,右边以及左边的最大元素,来计算雨水面积。单调栈是按行来计算雨水,栈是按递增的顺序,一旦发现添加的柱子高度大于栈头元素,此时出现凹槽,栈头元素是凹槽底部的柱子,栈头的第二个元素是凹槽左边的柱子,而添加的元素是凹槽右边的柱子。遇到相同高度的柱子,就将栈里的元素弹出,再加入新的元素。
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
stack = [0]
res = 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 len(stack) > 0 and height[i] > height[stack[-1]]:
cur = stack.pop()
if stack:
down = min(height[i], height[stack[-1]])
res += (down - height[cur]) * (i - stack[-1] -1)
stack.append(i)
return res
2. 84.柱状图中最大的矩形
题目链接:84.柱状图中最大的矩形
文档讲解: 代码随想录
对于每个柱子,找到左右两边第一个小于自己的元素,然后就可以求出以自己元素值为高的最大矩形面积。
暴力解法:会超时
class Solution(object):
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
res = 0
for i in range(len(heights)):
left = i
right = i
#寻找左边矮柱子
for _ in range(i,-1,-1):
if heights[left] < heights[i]:
break
left -= 1
#右边
for _ in range(i,len(heights)):
if heights[right] < heights[i]:
break
right += 1
width = right - left - 1
height = heights[i]
res = max(res, width*height)
return res
双指针:
class Solution(object):
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
n = len(heights)
#记录的矮柱子的下标,采用动态规划做,dp[i]表示包含i元素在内的矮柱子的下标
lheight_dp = [0] * n
rheight_dp = [0] * n
lheight_dp[0] = -1
for i in range(1,n):
temp = i - 1
while temp >= 0 and heights[temp] >= heights[i]:
temp = lheight_dp[temp]
#找到
lheight_dp[i] = temp
rheight_dp[-1] = n
for i in range(n-2,-1,-1):
temp = i + 1
while temp < n and heights[temp] >= heights[i]:
temp = rheight_dp[temp]
rheight_dp[i] = temp
res = 0
for i in range(n):
width = rheight_dp[i] - lheight_dp[i] - 1
height = heights[i]
res = max(res, height*width)
return res
单调栈:
为什么在heights数组后加0:如果数组本身就是升序的,入栈后就是降序,直到遍历结束都不会出现要入栈的元素值小于栈顶元素值的情况,这样子就不会计算矩阵面积,因此输出结果为0。
为什么在数组前加0:计算矩阵面积的三个要素,当前遍历的元素值,也就是判断完要入栈的元素值,也就是矩形的右边,栈顶第一个元素是当前矩形的高度,栈顶的第二个元素是左边,在数组前加0的目的在于是的栈顶第二个元素不为空。
class Solution(object):
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
heights.insert(0,0)
heights.append(0)
stack = [0]
res = 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]]:
cur = stack.pop()
if stack:
width = i - stack[-1] - 1
height = heights[cur]
res = max(res, height*width)
stack.append(i)
return res
class Solution(object):
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
#精简
heights.insert(0,0)
heights.append(0)
stack = []
res = 0
for i in range(len(heights)):
while stack and heights[i] < heights[stack[-1]]:
cur = stack.pop()
if stack:
width = i - stack[-1] - 1
height = heights[cur]
res = max(res, height*width)
stack.append(i)
return res