题目
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
提示:
n == height.length
0 <= n <= 3 * 104
0 <= height[i] <= 105
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/trapping-rain-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
1.暴力
- 初始化 ans=0ans=0
- 从左向右扫描数组:
- 初始化 \text{max_left}=0max_left=0 和 \text{max_right}=0max_right=0
- 从当前元素向左扫描并更新:
- \text{max_left}=\max(\text{max_left},\text{height}[j])max_left=max(max_left,height[j])
- 从当前元素向右扫描并更新:
- \text{max_right}=\max(\text{max_right},\text{height}[j])max_right=max(max_right,height[j])
- 将\min(\text{max_left},\text{max_right}) - \text{height}[i]min(max_left,max_right)−height[i] 累加到 \text{ans}ans
2.双指针
根据暴力法改进
由于每次都是找当前元素两边的最大值的比较小的一个,所以利用双指针,快速定位
定义left, right指针, left从左边扫描,right从右边开始扫描
定理:对left而言,left_max是可信的.对right而言,right_max是可信的
所以,从左边处理时,只要找到left_max
时间复杂度O(n)
const trap = function(height) {//双指针法let left = 0,right = height.length - 1,res = 0,left_max = 0,right_max = 0while (left <= right) {if (left_max < right_max) {res += Math.max(0, left_max - height[left])left_max = Math.max(left_max, height[left])left ++} else {res += Math.max(0, right_max - height[right])right_max = Math.max(right_max, height[right])right --}}return res};
3.单调栈
单调递减栈,形成中间洼地
第一次做的时候学(copy)的方法, 但还是忘了, 太菜了
思路,每次与前面元素比较,比它小的都可以根据栈顶元素和当前元素的较小的那个存水
- 从头开始扫描
- 如果stack不为空,将当前元素与栈顶元素比较,如果小于栈顶元素,说明它右边还没有墙壁让他盛水
- 如果大于栈顶元素,说明栈顶元素上方时可以盛水的
- 将栈顶元素出栈,(注意如果新的栈顶元素与之前的栈顶元素相等,也一起出栈可以减小时间复杂度)
- 计算盛水量(min(stack[stack.length - 1], height[i]) - height[top] ) * (i - stack[stack.length] - 1)
循环结束后,当前i入栈
class Solution:def trap(self, height: List[int]) -> int:#每个柱子顶部的储水量:该柱子左右两侧最大值中最小的量减去该值(这里只计算这个柱子\#顶部的水)然后累加#单调栈方法if not height: return 0h_Len = len(height)stack = []res = 0for i in range(h_Len):while stack and height[stack[-1]] < height[i]:bottom = height[stack.pop()]#print(bottom)while stack and height[stack[-1]] == bottom:stack.pop()#print(stack)#print("bottom",bottom)#print(height[stack[-1]])#print(min(height[stack[-1]], height[i]))if stack:res += (min(height[stack[-1]], height[i]) - bottom) * (i - stack[-1] - 1)#print(res)stack.append(i)return res
4.动态规划
未完待续…
