题目
- Trapping Rain Water
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
思路:
(1)首先给出暴力求解的方法:(这种方法我提交的时候是时间超出的,但我们后面去改进的,还是很有用的)
这个思路的关键点就是我们在每个位置去计算出该位置能存储多少水,然后将所有位置的水全部加起来就行了。
但是关键是我们应该怎么得到当前位置能存储多少水呢??仔细想想下面这个想法对不对:对每个位置,记为index, 我们得到从最左边到当前位置中,柱子最高的高度,记为left_max,,从当前位置到最右边得出柱子最高的高度,记为right_max,然后根据木桶效应,取left_max和right_max中较小者,然后减去当前位置的柱子高度,就得到当前位置能储几个单位的水了,最后将所有位置的水累加就是结果了。
class Solution:
def trap(self, height: List[int]) -> int:
ans =0
for i in range(len(height)):
left_max, right_max = 0, 0
for j in range(i + 1):
left_max = max(left_max, height[j])
for j in range(i, len(height)):
right_max = max(right_max, height[j])
high = min(left_max, right_max)
ans += (high - height[i])
return ans
(2)动态规划
上面算法存在的最大的开销就是每次移动到一个位置,都得重新去获取当前位置左边、右边的最高柱子的高度,实际上我们可以分别遍历height两次,找出每个位置最左边的最高柱子的高度,存到一个数组left_max中,同理构建一个另一个数组right_max.
所以得到如下算法:
class Solution:
def trap(self, height: List[int]) -> int:
left_max, right_max, ans = [], [], 0
for i in height:
if not left_max: left_max.append(i)
else: left_max.append(max(i, left_max[-1]))
for i in height[::-1]:
if not right_max: right_max.append(i)
else: right_max.append(max(i, right_max[-1]))
right_max = right_max[::-1]
for i in range(len(height)):
high = min(left_max[i], right_max[i])
ans += (high - height[i])
return ans
(3)栈(stack)这个是这一讲的重点,也是难点
首先,栈是用来存储位置索引的,当栈不为空且当前位置的高度大于栈顶元素位置对应的高度(条件),就将栈顶元素弹出,记为index,然后我们要计算这个位置能存储多少水,我们就在将这个位置前一个位置(也就是当前已经弹出index的stack的top元素0)的高度得出,即为pre, 然后计算当前位置和pre之间的距离,计算高度,然后加入到ans中,继续循环直到不满足条件,最后将当前位置压入栈,遍历每个元素,最终返回ans
class Solution:
def trap(self, height: List[int]) -> int:
stack, ans = [], 0
for i in range(len(height)):
while (stack and height[i] > height[stack[-1]]):
top = stack[-1]
stack.pop()
if not stack:
break
distance = i - stack[-1] - 1
bounded_height = min(height[i], height[stack[-1]]) - height[top]
ans += distance * bounded_height
stack.append(i)
return ans
(4)双指针
class Solution:
def trap(self, height: List[int]) -> int:
if not height: return 0
n = len(height)
left,right = 0, n - 1
maxleft,maxright = height[0],height[n - 1]
ans = 0
while left <= right:
maxleft = max(height[left],maxleft)
maxright = max(height[right],maxright)
if maxleft < maxright:
ans += maxleft - height[left]
left += 1
else:
ans += maxright - height[right]
right -= 1
return ans
参考文献
【1】42. Trapping Rain Water
【2】官方题解