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

1 2 3
| 输入: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:
1 2
| 输入:height = [4,2,0,3,2,5] 输出:9
|
提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
2,思考过程
我自己最开始想到的是双指针解决问题,接水取决于短板在哪里,所以优先动短板即可
在看了官方的题解后,发现动态规划解法、单调栈解法
3,代码处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| import java.util.Deque; import java.util.LinkedList; import java.util.Stack;
public class _42接雨水 {
public int trap(int[] height) { int left = 0; int heighLeft = 0;
int right = height.length - 1; int heighRight = 0;
int container = 0; while (left <= right) { if (height[left] <= height[right]) { if (heighLeft <= height[left]) { heighLeft = height[left]; } else { container += (heighLeft - height[left]); } left++; } else { if (heighRight <= height[right]) { heighRight = height[right]; } else { container += (heighRight - height[right]); } right--; } } return container; }
public int trap_gov_monotonic_stack(int[] height) { int ans = 0; Deque<Integer> stack = new LinkedList<Integer>(); int n = height.length; for (int i = 0; i < n; ++i) { while (!stack.isEmpty() && height[i] > height[stack.peek()]) { int top = stack.pop(); if (stack.isEmpty()) { break; } int left = stack.peek(); int currWidth = i - left - 1; int currHeight = Math.min(height[left], height[i]) - height[top]; ans += currWidth * currHeight; } stack.push(i); } return ans; }
public int trap_gov_dynamic(int[] height) { int[] leftMax = new int[height.length]; int[] rightMax = new int[height.length];
for (int i = 1; i < height.length; i++) { leftMax[i] = Math.max(height[i], height[i - 1]); leftMax[i] = Math.max(leftMax[i], leftMax[i - 1]); }
for (int i = height.length - 2; i >= 0; i--) { rightMax[i] = Math.max(height[i], height[i + 1]); rightMax[i] = Math.max(rightMax[i], rightMax[i + 1]); }
int container = 0; for (int i = 0; i < height.length; i++) { int min = Math.min(leftMax[i], rightMax[i]); if (min > height[i]) { container += min - height[i]; } } return container; }
public int trap_gov_double_index(int[] height) { int ans = 0; int left = 0, right = height.length - 1; int leftMax = 0, rightMax = 0; while (left < right) { leftMax = Math.max(leftMax, height[left]); rightMax = Math.max(rightMax, height[right]); if (height[left] < height[right]) { ans += leftMax - height[left]; ++left; } else { ans += rightMax - height[right]; --right; } } return ans; }
public static void main(String[] args) { _42接雨水 trap = new _42接雨水(); System.out.println(trap.trap_gov_monotonic_stack(new int[]{4,1,1,6})); } }
|
4,思考过程
动态规划解法:
1️⃣一个坑中,可以存水的多少取决于左右边界的最小值 Min(left、right)-heigh[i]>0时成立
2️⃣直接找到左边界、右边界的最大值数组即可
单调栈解法(需要review加深印象):
1️⃣假设右边可能有一个很高的挡板,我们暂时只考虑左边的低挡板就行
2️⃣如果这个坑的左边界高,那么表示可以积水,否则不能积水会流走
3️⃣当前这个坑比左边边界高时,那么计算一波前面积攒的水(一直计算到无法进行积水为止)