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.
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.
For each bar we aim to figure out how much rainwater exists above it. Look at the diagram below:
For rainwater to be on a bar, the height of bar should be less than (one of the bars on its left && one of the bars on its right) - i.e. trapped by the reservoir walls
Look at bar 2, there is no bar on the left that is taller than it, therefore it does not have any water on top of it.
Lets look at bar 5. We know that that 4 units of water exist above it. How did we get here?
If we look closely, we arrived at the solution by first looking on the left of Bar 5 and finding the max height on the left side which is Bar 2, and then looking on the right of Bar 5 and finding the max height which is Bar 6. Finally the minimum(Bar 2 , Bar 6) - Bar 5 gave our solution which is 4 unit of water.
Algorithm:
1: With given towerHeight array, create 2 arrays, leftMax and rightMax.
leftMax[i] - max height on left side of heights[i].
rightMax[i] - max height on right side of heights[i].
2: Calculate for each tower:
rainwater = rainwater + Max(Min(leftMax[i], rightMax[i]) - heights[i], 0);
// we cannot have (negative height)
// e.g. heights: 0 3 2 1 5 1
// leftMax: 0 0 3 3 3 5
// rightMax: 5 5 5 5 1 0
// leftMax[0] and rightMax[heights.length - 1] will be 0 (edges of the reservoir - so no max)
// what that means is?
// for index 1 -> height = 3
// 0 is its left max, 5 is its right max
// that gives zero volumn as it cannot hold water (draw it out)
// for index 2 -> height 2
// 3 is its left max and 5 is its right max -> min(3,5) = 3
// and height 2 is the bottom of the water bed
// so that gives (3-2) -> 1 volumn of water
var rainWaterCollector = function(height) {
var leftMax = [0];
var rightMax= [];
rightMax[height.length - 1] = 0
var water = 0;
// to get the left of i so we do i - 1
for(var i = 1; i < height.length; i++) {
leftMax[i] = Math.max(leftMax[i - 1], height[i - 1]);
}
for(i = height.length - 2; i >= 0; i--) {
rightMax[i] = Math.max(rightMax[i + 1], height[i + 1]);
var minHeight = Math.min(leftMax[i], rightMax[i]);
var waterBottom = height[i];
if(minHeight > waterBottom) {
water += (minHeight - waterBottom);
}
}
return water;
};
// vol = 7
var a = [0,0,1,2,4,3,2,5,0,0,2,1]
console.log('collection device "a" can hold', rainWaterCollector(a))
// vol = 6
var b = [0,1,0,2,1,0,1,3,2,1,2,1]
console.log('collection device "b" can hold', rainWaterCollector(b))
// vol = 12
var c =[0,3,0,1,0,0,0,1,0,2]
console.log('collection device "c" can hold', rainWaterCollector(c))
// vol = 8
var d = [0,1,0,3,5,0,0,0,2,0,1]
console.log('collection device "d" can hold', rainWaterCollector(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', rainWaterCollector(e))
Instead of summing the volume vertically, we can think about how much volume exists in a horizontal plane at each incremental height.
The 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.