From f142ca00b27dbf5c7c297843b5a609475c3e651e Mon Sep 17 00:00:00 2001 From: Keoni Garner Date: Fri, 27 Jul 2018 02:25:15 -0700 Subject: [PATCH] Add rain-terraces (trapping rain water) algorithm (#112) * Add rain-terraces (trapping rain water) algorithm * Fixed linting errors * Fixed linting errors --- .../uncategorized/rain-terraces/README.md | 53 +++++++++++++ .../rain-terraces/rainTerraces.js | 77 +++++++++++++++++++ .../rain-terraces/spec/rainTerraces.test.js | 12 +++ 3 files changed, 142 insertions(+) create mode 100644 src/algorithms/uncategorized/rain-terraces/README.md create mode 100644 src/algorithms/uncategorized/rain-terraces/rainTerraces.js create mode 100644 src/algorithms/uncategorized/rain-terraces/spec/rainTerraces.test.js diff --git a/src/algorithms/uncategorized/rain-terraces/README.md b/src/algorithms/uncategorized/rain-terraces/README.md new file mode 100644 index 00000000..a5b1b18e --- /dev/null +++ b/src/algorithms/uncategorized/rain-terraces/README.md @@ -0,0 +1,53 @@ +# Rain Terraces (Trapping Rain Water) Problem + +Given an array of non-negative integers representing terraces in an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. + +![Rain Terraces](https://www.geeksforgeeks.org/wp-content/uploads/watertrap.png) + +## Examples + +**Example #1** + +``` +Input: arr[] = [2, 0, 2] +Output: 2 +Structure is like below +| | +|_| +We can trap 2 units of water in the middle gap. +``` + +**Example #2** + +``` +Input: arr[] = [3, 0, 0, 2, 0, 4] +Output: 10 +Structure is like below + | +| | +| | | +|__|_| +We can trap "3*2 units" of water between 3 an 2, +"1 unit" on top of bar 2 and "3 units" between 2 +and 4. See below diagram also. +``` + +**Example #3** + +``` +Input: arr[] = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1] +Output: 6 + | + | || | +_|_||_|||||| +Trap "1 unit" between first 1 and 2, "4 units" between +first 2 and 3 and "1 unit" between second last 1 and last 2 +``` + +## Algorithms + + + +## References + +- [GeeksForGeeks](https://www.geeksforgeeks.org/trapping-rain-water/) diff --git a/src/algorithms/uncategorized/rain-terraces/rainTerraces.js b/src/algorithms/uncategorized/rain-terraces/rainTerraces.js new file mode 100644 index 00000000..037416a0 --- /dev/null +++ b/src/algorithms/uncategorized/rain-terraces/rainTerraces.js @@ -0,0 +1,77 @@ +/** + * @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; + + while (start < end) { + // Loop to find left max + while (start < end && terraces[start] <= terraces[start + 1]) { + start += 1; + } + leftMax = terraces[start]; + + // Loop to find right max + while (end > start && terraces[end] <= terraces[end - 1]) { + end -= 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; + } + } else { + // Move from left to right and collect water + end -= 1; + while (end > start && terraces[end] <= rightMax) { + water += rightMax - terraces[end]; + end -= 1; + } + } + } + return water; +} diff --git a/src/algorithms/uncategorized/rain-terraces/spec/rainTerraces.test.js b/src/algorithms/uncategorized/rain-terraces/spec/rainTerraces.test.js new file mode 100644 index 00000000..fba48172 --- /dev/null +++ b/src/algorithms/uncategorized/rain-terraces/spec/rainTerraces.test.js @@ -0,0 +1,12 @@ +import rainTerraces from '../rainTerraces'; + +describe('rainTerraces', () => { + it('should find the amount of water collected after raining', () => { + expect(rainTerraces([2, 0, 2])).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); + }); +});