原题:接雨水
思路:求每一列上的雨水体积,加起来得到结果
思路
经过简单观察可以得知:
首先需要找到该列两侧最高的列 maxL
和 maxR
接着拿两列中较矮的那一列减去当前列高度得到当前列雨水体积 cur = height[i] - min(maxL, maxR)
得到的结果若大于 0,雨水体积 += 该结果 result += cur
1. 找到该列两侧最高的列
如果根据思路正常的实现,那么每次循环都要从当前列往两侧寻找最高列,非常耗时
为了减少时间复杂度,我们可以用两个数组来存储每个列左右两侧的最高列:
1 2 3 4 5 6 7
| const maxL = [];
maxL[0] = 0;
const maxR = [];
maxR[height.length - 1] = 0;
|
根据简单的推导可以得知:
当前列左侧最高列等于 当前列左侧首列 和 其列的左侧最大值 中的 较高列:
maxL[i] = max(height[i - 1], maxL[i - 1])
当前列右侧最高列等于 当前列右侧首列 和 其列的右侧最大值 中的 较高列:
maxR[i] = max(height[i + 1], maxR[i + 1])
实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
for (let i = 1; i < height.length; i++) { maxL[i] = Math.max(maxL[i - 1], height[i - 1]); }
for (let i = height.length - 2; i >= 0; i--) { maxR[i] = Math.max(maxR[i + 1], height[i + 1]); }
|
2. 遍历列,计算每一列上的水体积
直接上实现:
1 2 3 4 5 6 7 8 9 10 11
| for (let i = 1; i < height.length - 1; i++) { const min = Math.min(maxL[i], maxR[i]); if (min > height[i]) { result += min - height[i]; } } return result;
|
完整代码
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
|
var trap = function (height) { let result = 0;
const maxL = []; maxL[0] = 0;
const maxR = []; maxR[height.length - 1] = 0;
for (let i = 1; i < height.length; i++) { maxL[i] = Math.max(maxL[i - 1], height[i - 1]); }
for (let i = height.length - 2; i >= 0; i--) { maxR[i] = Math.max(maxR[i + 1], height[i + 1]); }
for (let i = 1; i < height.length - 1; i++) { const min = Math.min(maxL[i], maxR[i]); if (min > height[i]) { result += min - height[i]; } } return result; };
|