From f07e96ec591339c4afab342de2172f75efaec927 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Fri, 27 Jul 2018 14:04:37 +0300 Subject: [PATCH] Refactor dynamic programming approach of Trapping Rain Water problem. --- .../rain-terraces/dpRainTerraces.js | 98 ++++++------------- 1 file changed, 29 insertions(+), 69 deletions(-) diff --git a/src/algorithms/uncategorized/rain-terraces/dpRainTerraces.js b/src/algorithms/uncategorized/rain-terraces/dpRainTerraces.js index f4bb7c30..1c48cbd8 100644 --- a/src/algorithms/uncategorized/rain-terraces/dpRainTerraces.js +++ b/src/algorithms/uncategorized/rain-terraces/dpRainTerraces.js @@ -5,81 +5,41 @@ * @return {number} */ export default function dpRainTerraces(terraces) { - /* - * STEPS - * - * 1. Find the highest terraces on the left and right side of the elevation map: - * e.g. for [0, 2, 4, 3, 4, 2, 4, 0, 8, 7, 0] we would have leftMax = 4 and rightMax = 8. - * This is because water will "trail off" the sides of the terraces. - * - * 2. At this point, we are essentially dealing with a new map: [4, 3, 4, 2, 4, 0, 8]. - * From here, we loop through the map from the left to the right if leftMax < rightMax - * (otherwise we move from right to left), adding water as we go unless we reach a value - * that is greater than or equal to leftMax or rightMax. - * e.g. [4, 3, 4, 2, 4, 0, 8] - * ^ - * water = water + (leftMax - 3) = 1 - * - * or if the terrace array was reversed: - * e.g. [8, 0, 4, 2, 4, 3, 4] - * ^ - * water = water + (rightMax - 3) = 1 - * - * 3. Again, we've essentially shortened the map: [4, 2, 4, 0, 8]. - * Now we repeat the above steps on the new array. - * - * Next Iteration: - * [4, 2, 4, 0, 8] - * ^ - * water = water + (leftMax - 2) = 3 - * - * Next Iteration: - * [4, 0, 8] - * ^ - * water = water + (leftMax - 0) = 7 - * - * 4. Return result: 7 - */ - let leftIndex = 0; - let rightIndex = terraces.length - 1; - - let leftMaxLevel = 0; - let rightMaxLevel = 0; - let waterAmount = 0; - while (leftIndex < rightIndex) { - // Loop to find the highest terrace from the left side. - while (leftIndex < rightIndex && terraces[leftIndex] <= terraces[leftIndex + 1]) { - leftIndex += 1; - } + // Init arrays that will keep the list of left and right maximum levels for specific positions. + const leftMaxLevels = new Array(terraces.length).fill(0); + const rightMaxLevels = new Array(terraces.length).fill(0); - leftMaxLevel = terraces[leftIndex]; + // Calculate the highest terrace level from the LEFT relative to the current terrace. + [leftMaxLevels[0]] = terraces; + for (let terraceIndex = 1; terraceIndex < terraces.length; terraceIndex += 1) { + leftMaxLevels[terraceIndex] = Math.max( + terraces[terraceIndex], + leftMaxLevels[terraceIndex - 1], + ); + } - // Loop to find the highest terrace from the right side. - while (rightIndex > leftIndex && terraces[rightIndex] <= terraces[rightIndex - 1]) { - rightIndex -= 1; - } + // Calculate the highest terrace level from the RIGHT relative to the current terrace. + rightMaxLevels[terraces.length - 1] = terraces[terraces.length - 1]; + for (let terraceIndex = terraces.length - 2; terraceIndex >= 0; terraceIndex -= 1) { + rightMaxLevels[terraceIndex] = Math.max( + terraces[terraceIndex], + rightMaxLevels[terraceIndex + 1], + ); + } - rightMaxLevel = terraces[rightIndex]; + // Not let's go through all terraces one by one and calculate how much water + // each terrace may accumulate based on previously calculated values. + for (let terraceIndex = 0; terraceIndex < terraces.length; terraceIndex += 1) { + // Pick the lowest from the left/right highest terraces. + const currentTerraceBoundary = Math.min( + leftMaxLevels[terraceIndex], + rightMaxLevels[terraceIndex], + ); - // Determine which direction we need to go. - if (leftMaxLevel < rightMaxLevel) { - // Move from left to right and collect water. - leftIndex += 1; - - while (leftIndex < rightIndex && terraces[leftIndex] <= leftMaxLevel) { - waterAmount += leftMaxLevel - terraces[leftIndex]; - leftIndex += 1; - } - } else { - // Move from right to left and collect water. - rightIndex -= 1; - - while (leftIndex < rightIndex && terraces[rightIndex] <= rightMaxLevel) { - waterAmount += rightMaxLevel - terraces[rightIndex]; - rightIndex -= 1; - } + if (currentTerraceBoundary > terraces[terraceIndex]) { + waterAmount += currentTerraceBoundary - terraces[terraceIndex]; } }