xamples
epeat
ode
pproach
ptimize
est
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. Determine how much rain you could possibly collect at once.
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: Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.
Instead of summing the volume vertically, we can 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',
summing the total amount of volume at that level,
decrementing the height by 1 and
repeating the process until a height of 0 is reached.
// 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 volume = 0;
var maxVal = 0;
arr.forEach(function(elem){
if(elem > maxVal) maxVal = elem;
})
//look at horizontal layers to determine volume
for(let height = maxVal; height>0; height--){
let positions = [];
//find indices of 'peaks' at each height
for(let j = 0; j < arr.length; j++){
if(arr[j] >= height) positions.push(j);
}
//find the volume at each layer
volume = positions.reduce(function(accVol, curr, index){
//the current peak index minus the previous peak index - 1
//e.g. index 3 - index 0 - 1 gives a volume of 2 as expected
if(index > 0) return accVol + (curr - positions[index - 1] - 1);
return acc;
}, volume)
}
return volume;
}
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
function rainCollector(arr){
var volume = 0; //space O(1)
var maxVal = 0; //space O(1)
arr.forEach(function(elem){ //time O(n) - 'n' being input array length
if(elem > maxVal) maxVal = elem; //time O(1)
})
for(let height = maxVal; height>0; height--){ //time O(h) - 'h' being height
let positions = []; //space O(n) as a max
for(let j = 0; j < arr.length; j++){ //time O(n)
if(arr[j] >= height) positions.push(j); //time O(1)
}
volume = positions.reduce(function(accVol, curr, index){
if(index > 0) return accVol + (curr - positions[index - 1] - 1);
return acc; //time O(1)
}, volume) //time O(n) max
}
return volume;
}
//Overall (after reducing) -- time O(h*n), space O(n)
function rainCollector(arr){
var leftMax = [], rightMax = [], max = 0, volume = 0;
//make arrays the same length as the input,
// containing max heights at each index
for(let i = 0; i < arr.length; i++){
max = arr[i] > max ? arr[i] : max;
leftMax[i] = max;
}
max = 0; //reset max
for(let i = arr.length - 1; i >= 0; i--){
max = arr[i] > max ? arr[i] : max;
rightMax[i] = max;
}
//Go through the array summing vertically based on peaks
//Don't forget to subtract the value of the element itself
arr.forEach((el, i) => {
volume += Math.min(leftMax[i], rightMax[i]) - el;
})
return volume;
}
function rainCollector(arr){
var rightMax = [], max = 0, volume = 0;
for(let i = arr.length - 1; i >= 0; i--){
max = arr[i] > max ? arr[i] : max;
rightMax[i] = max;
}
max = 0;
for(let i = 0; i < arr.length; i++){
max = arr[i] > max ? arr[i] : max;
volume += Math.min(max, rightMax[i]) - arr[i];
}
return volume;
}