This community-built FAQ covers the “Capturing Rainwater” code challenge in JavaScript. You can find that challenge here, or pick any challenge you like from our list.
Top Discussions on the JavaScript challenge Capturing Rainwater
There are currently no frequently asked questions or top answers associated with this challenge – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this challenge. Ask a question or post a solution by clicking reply () below.
If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this challenge, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.
Join the Discussion. Help a fellow learner on their journey.
Ask or answer a question about this exercise by clicking reply () below!
You can also find further discussion and get answers to your questions over in #get-help.
Agree with a comment or answer? Like () to up-vote the contribution!
function capturingRainwater(heights) {
return heights.map((n, i) =>
Math.max(0, Math.min(
Math.max(...heights.slice(i + 1)),
Math.max(...heights.slice(0, i))
) - n)
).reduce((a, b) => a + b, 0);
}
const testArray = [4, 2, 1, 3, 0, 1, 2];
console.log(capturingRainwater(testArray));
// Leave this so that we can test your code:
module.exports = capturingRainwater;
function capturingRainwater(heights) {
// amount of captured water
let water = 0;
// looping each row (bottom to up)
for(let i_row = 0; i_row < Math.max(...heights); i_row++) {
// looping inside row, cell by cell (left to right)...
// and finding out if cell is filled with water...
for(let i_col = 0; i_col < (heights.length); i_col++) {
// if current cell contains water...
// then all following tests must result true
// TEST 1/3
// cell must not be "solid"
let notSolid = ((heights[i_col] - i_row) > 0) ? false : true;
if(notSolid===false) {continue} // skip rest of the code block
// TEST 2/3
// cell must not be part outer column
let notOuter = (i_col == 0 || i_col == (heights.length - 1)) ? false : true;
if(notOuter===false) {continue} // skip rest of the code block
// TEST 3/3
// at least 1 solid cell must be present in each direction from current position (to left and to right)
let isBuried = isCellBuried(heights, i_row, i_col);
if(isBuried===false) {continue} // skip rest of the code block
// above tests result true...
// add 1 to amount of captured water
water++;
}
}
return water;
}
// testing if given cell with given coordinates (rowId, colId) in given array of heights (heightsArr) is horizontally surrounded with at least one "solid cell" in each direction (all the way to the left and to the right)
function isCellBuried(heightsArr, rowId, colId) {
// this array will map items in given row
// items:
// solid block as true (solidBlock = true)
// non-block as false (solidBlock = false)
let rowMap = [];
// mapping solid and non-solid blocks inside array row
heightsArr.forEach((item, index) => {
let solidBlock = (item - rowId) > 0 ? true : false;
rowMap.push(solidBlock);
})
// slicing the array row into two array parts (left and right)
// given column from argument being delimiter
// current cell and outer cells are not included
let leftPart = rowMap.slice(0, colId);
let rightPart = rowMap.slice((colId + 1), heightsArr.length);
// testing if both of the parts contain at least one solid block
// if yes, then current cell is able to contain water
let cellInHole = (leftPart.includes(true) && rightPart.includes(true)) ? true : false;
return cellInHole;
}
const testArray = [4, 2, 1, 3, 0, 1, 2];
console.log(capturingRainwater(testArray));
// Leave this so that we can test your code:
module.exports = capturingRainwater;
function capturingRainwater(heights) {
// amount of captured water
let water = 0;
// looping each row (bottom to up)
for(let i_row = 0; i_row < Math.max(...heights); i_row++) {
// looping inside row, cell by cell (left to right)...
// and finding out if cell is filled with water...
for(let i_col = 0; i_col < (heights.length); i_col++) {
// if current cell contains water...
// then all following tests must result true
// TEST 1/3
// cell must not be "solid"
let notSolid = ((heights[i_col] - i_row) > 0) ? false : true;
if(notSolid===false) {continue} // skip rest of the code block
// TEST 2/3
// cell must not be part outer column
let notOuter = (i_col == 0 || i_col == (heights.length - 1)) ? false : true;
if(notOuter===false) {continue} // skip rest of the code block
// TEST 3/3
// at least 1 solid cell must be present in each direction from current position (to left and to right)
let isBuried = isCellBuried(heights, i_row, i_col);
if(isBuried===false) {continue} // skip rest of the code block
// above tests result true...
// add 1 to amount of captured water
water++;
}
}
return water;
}
// testing if given cell with given coordinates (rowId, colId) in given array of heights (heightsArr) is horizontally surrounded with at least one "solid cell" in each direction (all the way to the left and to the right)
function isCellBuried(heightsArr, rowId, colId) {
// this array will map items in given row
// items:
// solid block as true (solidBlock = true)
// non-block as false (solidBlock = false)
let rowMap = [];
// mapping solid and non-solid blocks inside array row
heightsArr.forEach((item, index) => {
let solidBlock = (item - rowId) > 0 ? true : false;
rowMap.push(solidBlock);
})
// slicing the array row into two array parts (left and right)
// given column from argument being delimiter
// current cell and outer cells are not included
let leftPart = rowMap.slice(0, colId);
let rightPart = rowMap.slice((colId + 1), heightsArr.length);
// testing if both of the parts contain at least one solid block
// if yes, then current cell is able to contain water
let cellInHole = (leftPart.includes(true) && rightPart.includes(true)) ? true : false;
return cellInHole;
}
const testArray = [4, 2, 1, 3, 0, 1, 2];
console.log(capturingRainwater(testArray));
// Leave this so that we can test your code:
module.exports = capturingRainwater;
I don’t think mine is much good because the code for mine is really, really long.
I started by finding the max and its index, and then found the volume to the next peak to the left repeatedly, and to the next peak to the right repeatedly.
I created a lot of helper functions for individual tasks, like finding the volume between two indices, in mine.
My solution
function capturingRainwater(heights) {
const length = heights.length;
if (length <= 1) {
return 0;
}
let volume_total = 0;
let max_so_far = 0;
let index_of_max = 0;
for (let i = 0; i < length; i++) {
if (heights[i] > max_so_far) {
max_so_far = heights[i];
index_of_max = i;
}
}
const max = max_so_far;
if (max == 0) {
return 0;
}
let indexByHeight = Array(max + 1);
for (let h = 0; h <= max; h++) {
indexByHeight[h] = [];
}
for (let i = 0; i < length; i++) {
indexByHeight[heights[i]].push(i);
}
function getVolumeBetweenIndices(a, b) {
if ((a < 0) || (b < 0)) {
return 0;
}
else if ((a >= length) || (b >= length)) {
return 0;
}
else if (a == b) {
return 0;
}
else if (a > b) {
let temp = a;
a = b;
b = temp;
}
const a_h = heights[a];
const b_h = heights[b];
const level = (a_h < b_h) ? a_h : b_h;
let volume = 0;
for (let j = a + 1; j < b; j++) {
let depth = level - heights[j];
//console.log(` >> @[${j}] +${depth}`);
if (depth > 0) {
volume += depth;
}
}
//console.log(`@(${a},${b}) +${volume} using level=${level}` );
return (volume > 0) ? volume : 0;
}
function getNextMaxIndex(index) {
let current_height = 0;
let previous_height = 0;
let next_max = 0;
let next_max_index = (index > 0) ? index : 0;
for (i = index; i < length; i++) {
current_height = heights[i];
if (current_height > previous_height) {
next_max = current_height;
next_max_index = i;
}
previous_height = current_height;
}
return next_max_index;
}
function getNextMaxIndexReversed(index) {
let current_height = 0;
let previous_height = 0;
let next_max = 0;
let next_max_index = (index > 0) ? index : length - 1;
for (i = index; i >= 0; i--) {
current_height = heights[i];
if (current_height > previous_height) {
next_max = current_height;
next_max_index = i;
}
previous_height = current_height;
}
return next_max_index;
}
const lastOf = arr => arr[arr.length - 1];
const lowerMaxIndex = indexByHeight[max][0];
const upperMaxIndex = lastOf(indexByHeight[max]);
//console.log(lowerMaxIndex + ", " + upperMaxIndex);
volume_total += getVolumeBetweenIndices(lowerMaxIndex, upperMaxIndex);
//console.log(volume_total + " at j=" + max);
let previous_lower = lowerMaxIndex;
let previous_upper = upperMaxIndex;
let lower_index = lowerMaxIndex - 1;
let upper_index = upperMaxIndex + 1;
for (let j = max - 1; j > 0; j--) {
if (indexByHeight[j]) {
const atThisHeight = indexByHeight[j];
if (atThisHeight.length > 0) {
let first = atThisHeight[0];
let last = lastOf(atThisHeight);
if (first < lower_index) {
lower_index = first;
volume_total += getVolumeBetweenIndices(lower_index, previous_lower);
previous_lower = lower_index;
}
if (last > upper_index) {
upper_index = last;
volume_total += getVolumeBetweenIndices(previous_upper, upper_index);
previous_upper = upper_index;
}
//console.log(volume_total + " at j=" + j);
}
}
}
return volume_total;
}
const testArray = [4, 2, 1, 3, 0, 1, 2];
console.log(capturingRainwater(testArray));
const capturingRainwater = heights => {
let totalRainWater = 0;
heights.forEach((height, index) => {
// Don't find water for left and right bounds
if(index === 0 || index === heights.length - 1) return;
// Find the max height on both sides of the current column
let leftMax = Math.max(...heights.slice(0, index));
let rightMax = Math.max(...heights.slice(index + 1, heights.length));
// Calculate the water for the current column
let curColWater = Math.min(leftMax, rightMax) - height
// Only add positive water
if(curColWater <= 0) return
totalRainWater += curColWater
})
return totalRainWater;
}
const testArray = [4, 2, 1, 3, 0, 1, 2];
console.log(capturingRainwater(testArray));
// Leave this so that we can test your code:
module.exports = capturingRainwater;
function capturingRainwater(heights) {
let sum = 0;
let level = 1;
while (true) {
let hasLeftBound = false;
let water = 0;
let waterAdded = false;
let maxCountInLine = 0;
let mayBeHigher = false;
for (let i = 0; i < heights.length; i++) {
if (heights[i] >= level) {
if (water) {
waterAdded = true;
sum += water;
water = 0;
}
hasLeftBound = true;
maxCountInLine++;
if (maxCountInLine === 3) {
mayBeHigher = true;
}
} else {
maxCountInLine = 0;
if (hasLeftBound) {
water++;
}
}
}
if (!waterAdded && !mayBeHigher) break;
level++;
waterAdded = false;
}
return sum;
}