Given an array of numbers:
1 2 3 4 6 3 2 4 7 3 4 6 1 2 1
Each number in this array indicates height. The combination of heights forms a two-dimensional landscape.
Imagine that it is raining and water accumulates in the pits of this landscape. It is necessary to calculate how many cells the water fills.
The ideal solution to this problem involves passing through the array once.
Implement on js with the input of an array of numbers and schematic visualization of the landscape, as well as the output of the result.
Graphic output made via chart.js http://prntscr.com/mthgtk
Here is a solution
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="./data.js"></script> </head> <style> #app { display: flex; padding-top: 100px; padding-left: 200px; } .cube { height: 50px; width: 50px; background-color: gray; margin:1px; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: bold; color: brown; } .column { display: flex; flex-direction: column-reverse; } .water { height: 50px; width: 50px; background-color: rgb(26, 123, 187); margin:1px; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: bold; color: brown; } </style> <body> <div id="app"> </div> </body> </html>
Js
window.onload = () => { const app = document.getElementById('app'); const coors = [1, 2, 3, 4, 6, 3, 2, 4, 7, 3, 4, 6, 1, 2, 1]; const highest = coors.map(v => v).sort().reverse()[0]; for (const el of coors) { let col = createColumn(); for (let i = 0; i < el; i++) { const cube = createCube(); cube.innerHTML = i + 1; col.appendChild(cube); } for (let j = 0; j < highest - el; j++) { const cube = createWater(); cube.innerHTML = j + 1; col.appendChild(cube); } app.appendChild(col); } var colums = Array.from(app.getElementsByClassName('column')); var copy = Object.assign({}, colums); for (let index = 0; index < colums.length; index++) { if (colums[index - 1]) { const groundLeft = colums[index - 1].getElementsByClassName('cube').length; const groundCenter = colums[index].getElementsByClassName('cube').length; if ((groundLeft > groundCenter)) { Array .from(colums[index].getElementsByClassName('water')) .forEach(v => colums[index].removeChild(v)); } if ((groundLeft < groundCenter)) { Array .from(colums[index - 1].getElementsByClassName('water')) .forEach(v => colums[index - 1].removeChild(v)); } } } let picks = colums.map((v, i, a) => { const ind = Array.from(v.children).findIndex(z => z.classList.contains('water')); if ( ind> -1) { return { index: i, height: v.getElementsByClassName('cube').length }; } }); const picksAll = picks.filter(v => v).map((v, i, array) => { return { first: array[i], next: array[i + 1] } }).filter(v => v.first && v.next); for (const pick of picksAll) { const height = pick.first.height > pick.next.height ? pick.next.height : pick.first.height; const start = pick.first.index + 1; for (let i = start; i < pick.next.index; i++) { const need = height - copy[i].children.length; for (let j = 0; j < need; j++) { copy[i].appendChild(createWater()); } } Array.from(copy[pick.first.index].children).forEach((v, i, a) => { if (v.classList.contains('water')) { copy[pick.first.index].removeChild(v); } }); Array.from(copy[pick.next.index].children).forEach((v, i, a) => { if (v.classList.contains('water')) { copy[pick.next.index].removeChild(v); } }); } } function createColumn() { const column = document.createElement('div'); column.className = 'column'; return column; } function createCube() { const column = document.createElement('div'); column.className = 'cube'; return column; } function createWater() { const column = document.createElement('div'); column.className = 'water'; return column; }