From 6fc429975f453f14c70bd5ac79e2b43f4d403d25 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Fri, 27 Jul 2018 13:00:24 +0300 Subject: [PATCH] Add Rain Terraces problem. --- README.md | 1 + .../{spec => __test__}/rainTerraces.test.js | 9 ++ .../rain-terraces/rainTerraces.js | 130 ++++++++++-------- 3 files changed, 79 insertions(+), 61 deletions(-) rename src/algorithms/uncategorized/rain-terraces/{spec => __test__}/rainTerraces.test.js (53%) diff --git a/README.md b/README.md index 7835d8fa..633c8ed7 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples + * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) diff --git a/src/algorithms/uncategorized/rain-terraces/spec/rainTerraces.test.js b/src/algorithms/uncategorized/rain-terraces/__test__/rainTerraces.test.js similarity index 53% rename from src/algorithms/uncategorized/rain-terraces/spec/rainTerraces.test.js rename to src/algorithms/uncategorized/rain-terraces/__test__/rainTerraces.test.js index fba48172..5c4461b6 100644 --- a/src/algorithms/uncategorized/rain-terraces/spec/rainTerraces.test.js +++ b/src/algorithms/uncategorized/rain-terraces/__test__/rainTerraces.test.js @@ -2,11 +2,20 @@ import rainTerraces from '../rainTerraces'; describe('rainTerraces', () => { it('should find the amount of water collected after raining', () => { + expect(rainTerraces([1])).toBe(0); + expect(rainTerraces([1, 0])).toBe(0); + expect(rainTerraces([0, 1])).toBe(0); + expect(rainTerraces([0, 1, 0])).toBe(0); + expect(rainTerraces([0, 1, 0, 0])).toBe(0); + expect(rainTerraces([0, 1, 0, 0, 1, 0])).toBe(2); + expect(rainTerraces([0, 2, 0, 0, 1, 0])).toBe(2); expect(rainTerraces([2, 0, 2])).toBe(2); + expect(rainTerraces([2, 0, 5])).toBe(2); expect(rainTerraces([3, 0, 0, 2, 0, 4])).toBe(10); expect(rainTerraces([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])).toBe(6); expect(rainTerraces([1, 1, 1, 1, 1])).toBe(0); expect(rainTerraces([1, 2, 3, 4, 5])).toBe(0); expect(rainTerraces([4, 1, 3, 1, 2, 1, 2, 1])).toBe(4); + expect(rainTerraces([0, 2, 4, 3, 4, 2, 4, 0, 8, 7, 0])).toBe(7); }); }); diff --git a/src/algorithms/uncategorized/rain-terraces/rainTerraces.js b/src/algorithms/uncategorized/rain-terraces/rainTerraces.js index 037416a0..f2f15a9e 100644 --- a/src/algorithms/uncategorized/rain-terraces/rainTerraces.js +++ b/src/algorithms/uncategorized/rain-terraces/rainTerraces.js @@ -2,76 +2,84 @@ * @param {number[]} terraces * @return {number} */ - -/* - * STEPS - * 1. Find the highest terraces on the left and right side of the elevation map: - * e.g. [0, 2, 4, 3, 1, 2, 4, 0, 8, 7, 0] => (leftMax = 4, 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 || rightMax. - * e.g. [4, 3, 4, 2, 4, 0, 8] - * ^ - * water += leftMax - 3 => water = 1 - * or if the terrace array was reversed: - * e.g. [8, 0, 4, 2, 4, 3, 4] - * ^ - * water += rightMax - 3 => water = 1 - * - * 3. Again, we've essentially shortened the map: [4, 2, 4, 0, 8]. - * Now we repeat the above steps on the new array. - * e.g. - * Next Iteration: - * [4, 2, 4, 0, 8] - * ^ - * water += leftMax - 2 => water = 3 - * - * Next Iteration: - * [4, 0, 8] - * ^ - * water += leftMax - 0 => water = 7 - * - * return water(7) - */ export default function rainTerraces(terraces) { - let start = 0; - let end = terraces.length - 1; - let water = 0; - let leftMax = 0; - let rightMax = 0; + /* + * 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; - while (start < end) { - // Loop to find left max - while (start < end && terraces[start] <= terraces[start + 1]) { - start += 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; } - leftMax = terraces[start]; - // Loop to find right max - while (end > start && terraces[end] <= terraces[end - 1]) { - end -= 1; + leftMaxLevel = terraces[leftIndex]; + + // Loop to find the highest terrace from the right side. + while (rightIndex > leftIndex && terraces[rightIndex] <= terraces[rightIndex - 1]) { + rightIndex -= 1; } - rightMax = terraces[end]; - // Determine which direction we need to move in - if (leftMax < rightMax) { - // Move from left to right and collect water - start += 1; - while (start < end && terraces[start] <= leftMax) { - water += leftMax - terraces[start]; - start += 1; + rightMaxLevel = terraces[rightIndex]; + + // 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 left to right and collect water - end -= 1; - while (end > start && terraces[end] <= rightMax) { - water += rightMax - terraces[end]; - end -= 1; + // Move from right to left and collect water. + rightIndex -= 1; + + while (leftIndex < rightIndex && terraces[rightIndex] <= rightMaxLevel) { + waterAmount += rightMaxLevel - terraces[rightIndex]; + rightIndex -= 1; } } } - return water; + + return waterAmount; }