R
E
A
C
T
O
xamples
epeat
ode
pproach
ptimize
est
{Rainwater Collector}
The Question
You're an industrious programmer that lives off the grid. The local well that you use to fetch water has gone dry, so you've decided to collect rain water to filter. However, your collection device isn't flat.
PROBLEM: Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water your collection device is able to trap after raining.
Example
EXAMPLE: Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.
Keep in mind...
- Water will only gather up to the height of its reservoir walls.
- We can therefore think about this problem in terms of height.
- Water cannot be held in the first or last bar, due to no containing wall on one side.
The Approach
Instead of summing the volume vertically, we will think about how much volume exists in a horizontal plane at each incremental height.
Our solution goes about this by starting at the highest 'peak' and and summing the total amount of volume at that level then decrementing the height by 1 and repeating the process until a height of 0 is reached.
Tests to Run
// vol = 7
var a = [0,0,1,2,4,3,2,5,0,0,2,1]
console.log('collection device "a" can hold', totalVol(a))
// vol = 6
var b = [0,1,0,2,1,0,1,3,2,1,2,1]
console.log('collection device "b" can hold', totalVol(b))
// vol = 12
var c =[0,3,0,1,0,0,0,1,0,2]
console.log('collection device "c" can hold', totalVol(c))
// vol = 8
var d = [0,1,0,3,5,0,0,0,2,0,1]
console.log('collection device "d" can hold', totalVol(d))
// vol = 38
var e = [0,5,3,2,8,8,1,1,2,4,3,3,7,1,2,4,3,2]
console.log('collection device "e" can hold', totalVol(e))
'use strict'
function rainCollector(arr){
var collection = 0;
var maxVal = 0;
arr.forEach(function(elem){
if(elem > maxVal) maxVal = elem;
})
for(let i = maxVal; i>0; i--){
let positions = [];
for(let j = 0; j < arr.length; j++){
if(arr[j] >= i) positions.push(j);
}
collection = positions.reduce(function(acc, curr, index){
if(index > 0) return acc + (curr - positions[index - 1] - 1);
return acc;
}, collection)
}
return collection;
}
var rainArr = [0,5,3,2,8,8,1,1,2,4,3,3,7,1,2,4,3,2];
console.log(rainCollector(rainArr)); //logs 38
Alternate O(n) solution approach
- Find by rightward scan, the highest tower to the left of each position.
- Similarly, find by leftward scan the highest tower to the right of each position
- Take the minimum at each position and sum each up (be sure to subtract out towers already in place)
Alternate O(n) solution
function rainCollector(arr){
var leftMax = [], rightMax = [], max = 0;
for(let i = 0; i < arr.length; i++){
max = arr[i] > max ? arr[i] : max;
leftMax[i] = max;
}
max = 0;
for(let i = arr.length - 1; i >= 0; i--){
max = arr[i] > max ? arr[i] : max;
rightMax[i] = max;
}
var sum = 0;
for(let i = 0; i < arr.length; i++){
sum += Math.min(leftMax[i], rightMax[i]) - arr[i];
}
return sum;
}
Solution with comments:
Rainwater Collector
By pat310
Rainwater Collector
Technical interview problem for determining water collected between indices
- 1,546