法算day7

法算day7
lief接雨水
问题描述
给定 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
1 <= n <= 2 * 104
0 <= height[i] <= 105
问题分析
这个问题的关键在于理解:每个位置能接的雨水量取决于它左右两边的最高柱子。
对于每个位置,我们需要知道它左边的最高柱子和右边的最高柱子
这两个最高柱子中较矮的那个决定了水位的高度
水位高度减去当前位置的高度,就是这个位置能接的雨水量
这种方法的时间复杂度是O(n),因为我们只需要遍历数组三次(计算左边最大值、右边最大值和计算总雨水量)。空间复杂度是O(n),因为我们使用了两个辅助数组。
举例说明(动态规划法)
对于数组 [0,1,0,2,1,0,1,3,2,1,2,1]:
位置0:高度为0,左边最大值是0,右边最大值是3,能接的水量是min(0,3)-0=0
位置1:高度为1,左边最大值是1,右边最大值是3,能接的水量是min(1,3)-1=0
位置2:高度为0,左边最大值是1,右边最大值是3,能接的水量是min(1,3)-0=1
位置3:高度为2,左边最大值是2,右边最大值是3,能接的水量是min(2,3)-2=0
位置4:高度为1,左边最大值是2,右边最大值是3,能接的水量是min(2,3)-1=1
位置5:高度为0,左边最大值是2,右边最大值是3,能接的水量是min(2,3)-0=2
位置6:高度为1,左边最大值是2,右边最大值是3,能接的水量是min(2,3)-1=1
位置7:高度为3,左边最大值是3,右边最大值是3,能接的水量是min(3,3)-3=0
位置8:高度为2,左边最大值是3,右边最大值是2,能接的水量是min(2,3)-2=0
位置9:高度为1,左边最大值是3,右边最大值是2,能接的水量是min(2,3)-1=1
位置10:高度为2,左边最大值是3,右边最大值是2,能接的水量是min(2,3)-2=0
位置11:高度为1,左边最大值是3,右边最大值是1,能接的水量是min(3,1)-1=0
将所有位置的雨水量相加,就得到总雨水量6。
Java版(动态规划法)
1 | // 时间复杂度:O(n),空间复杂度:O(n) |
✅ 说明:
- 时间复杂度:O(n)
- 空间复杂度是 O(n),需要额外的O(n)空间来存储左右最大高度数组
java版(方法一:双指针法)
1 | public class TrapRainWater { |
✅ 说明:
- 时间复杂度:O(n)
- 空间复杂度是 O(1)
举例说明
对于数组 [0,1,0,2,1,0,1,3,2,1,2,1]:
- 初始状态
1
2
3
4
5height = [0,1,0,2,1,0,1,3,2,1,2,1]
索引: 0 1 2 3 4 5 6 7 8 9 10 11
left = 0, right = 11
leftMax = 0, rightMax = 0
water = 0 - 第1步:比较 height[0] 和 height[11]
1
2
3
4
5
6left=0, right=11
height[0]=0, height[11]=1
0 < 1 → 走if分支
height[0]=0 >= leftMax=0? 是 → 更新leftMax=0
left++ → left=1
结果: leftMax=0, rightMax=0, water=0 - 第2步:比较 height[1] 和 height[11]
1
2
3
4
5
6left=1, right=11
height[1]=1, height[11]=1
1 >= 1 → 走else分支
height[11]=1 >= rightMax=0? 是 → 更新rightMax=1
right-- → right=10
结果: leftMax=0, rightMax=1, water=0 - 第3步:比较 height[1] 和 height[10]
1
2
3
4
5
6left=1, right=10
height[1]=1, height[10]=2
1 < 2 → 走if分支
height[1]=1 >= leftMax=0? 是 → 更新leftMax=1
left++ → left=2
结果: leftMax=1, rightMax=1, water=0 - 第4步:比较 height[2] 和 height[10]
1
2
3
4
5
6left=2, right=10
height[2]=0, height[10]=2
0 < 2 → 走if分支
height[2]=0 >= leftMax=1? 否 → water += 1-0=1
left++ → left=3
结果: leftMax=1, rightMax=1, water=1 - 第5步:比较 height[3] 和 height[10]
1
2
3
4
5
6left=3, right=10
height[3]=2, height[10]=2
2 >= 2 → 走else分支
height[10]=2 >= rightMax=1? 是 → 更新rightMax=2
right-- → right=9
结果: leftMax=1, rightMax=2, water=1 - 第6步:比较 height[3] 和 height[9]
1
2
3
4
5
6left=3, right=9
height[3]=2, height[9]=1
2 >= 1 → 走else分支
height[9]=1 >= rightMax=2? 否 → water += 2-1=1
right-- → right=8
结果: leftMax=1, rightMax=2, water=2 - 第7步:比较 height[3] 和 height[8
1
2
3
4
5
6left=3, right=8
height[3]=2, height[8]=2
2 >= 2 → 走else分支
height[8]=2 >= rightMax=2? 是 → 更新rightMax=2
right-- → right=7
结果: leftMax=1, rightMax=2, water=2 - 第8步:比较 height[3] 和 height[7]
1
2
3
4
5
6left=3, right=7
height[3]=2, height[7]=3
2 < 3 → 走if分支
height[3]=2 >= leftMax=1? 是 → 更新leftMax=2
left++ → left=4
结果: leftMax=2, rightMax=2, water=2 - 第9步:比较 height[4] 和 height[7]
1
2
3
4
5
6left=4, right=7
height[4]=1, height[7]=3
1 < 3 → 走if分支
height[4]=1 >= leftMax=2? 否 → water += 2-1=1
left++ → left=5
结果: leftMax=2, rightMax=2, water=3 - 第10步:比较 height[5] 和 height[7]
1
2
3
4
5
6left=5, right=7
height[5]=0, height[7]=3
0 < 3 → 走if分支
height[5]=0 >= leftMax=2? 否 → water += 2-0=2
left++ → left=6
结果: leftMax=2, rightMax=2, water=5 - 第11步:比较 height[6] 和 height[7]
1
2
3
4
5
6left=6, right=7
height[6]=1, height[7]=3
1 < 3 → 走if分支
height[6]=1 >= leftMax=2? 否 → water += 2-1=1
left++ → left=7
结果: leftMax=2, rightMax=2, water=6 - 第12步:left=7, right=7
1
2left >= right → 循环结束
最终结果: water = 6
python版(双指针法)
1 | def trap(height): |









