题目描述
给定 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
思路&js代码
1、动态规划
对于下标 i,下雨后水能到达的最大高度等于下标 i 两边的最大高度的最小值,下标 i 处能接的雨水量等于下标 i 处的水能到达的最大高度减去 height[i]。
var trap = function(height) {
const n = height.length;
if (n == 0) {
return 0;
}
const leftMax = new Array(n).fill(0);
leftMax[0] = height[0];
for (let i = 1; i < n; ++i) {
leftMax[i] = Math.max(leftMax[i - 1], height[i]);
}
const rightMax = new Array(n).fill(0);
rightMax[n - 1] = height[n - 1];
for (let i = n - 2; i >= 0; --i) {
rightMax[i] = Math.max(rightMax[i + 1], height[i]);
}
let ans = 0;
for (let i = 0; i < n; ++i) {
ans += Math.min(leftMax[i], rightMax[i]) - height[i];
}
return ans;
};2、双指针
var trap = function(height) {
let ans = 0;
let left = 0, right = height.length - 1;
let 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;
};3、思路2的正向思考过程
试想被水填满后的情况,最高柱子左侧水位必然是递增的,右侧水位必然是递减的,不可能出现中间有凹的情况(凹会被水填满)。于是只要找到最高柱子的位置,左侧一次正向遍历,右侧一次反向遍历,即可实时计算水位并累计水位高度差作为积水量。
class Solution {
public:
int trap(vector<int>& height) {
int maxHeight = 0;
int maxHeightPos = -1;
for (int i=0;i<height.size();i++) {
if (height[i] > maxHeight) {
maxHeight = height[i];
maxHeightPos = i;
}
}
if (maxHeightPos == -1) return 0;
int waterHeight = 0;
int waterSum = 0;
for (int i=0;i<maxHeightPos;i++) {
// 左侧水位
if (height[i] > waterHeight) waterHeight = height[i];
waterSum += waterHeight - height[i];
}
waterHeight = 0;
for (int i=height.size()-1;i>maxHeightPos;i--) {
// 右侧水位
if (height[i] > waterHeight) waterHeight = height[i];
waterSum += waterHeight - height[i];
}
return waterSum;
}
};