Skip to content

Commit 340a71b

Browse files
committedJul 27, 2018
Add brute force solution of Rain Terraces problem.
1 parent 6fc4299 commit 340a71b

File tree

7 files changed

+131
-31
lines changed

7 files changed

+131
-31
lines changed
 

‎README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ a set of rules that precisely define a sequence of operations.
128128
* `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm
129129
* `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples
130130
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples
131-
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
131+
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions)
132132
* `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
133133
* `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
134134

@@ -140,6 +140,7 @@ algorithm is an abstraction higher than a computer program.
140140

141141
* **Brute Force** - look at all the possibilities and selects the best solution
142142
* `B` [Linear Search](src/algorithms/search/linear-search)
143+
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
143144
* `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
144145
* `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
145146
* **Greedy** - choose the best option at the current time, without any consideration for the future
@@ -164,6 +165,7 @@ algorithm is an abstraction higher than a computer program.
164165
* `B` [Fibonacci Number](src/algorithms/math/fibonacci)
165166
* `B` [Jump Game](src/algorithms/uncategorized/jump-game)
166167
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
168+
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
167169
* `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
168170
* `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
169171
* `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)

‎src/algorithms/uncategorized/rain-terraces/README.md

+50-8
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,58 @@ be stored in every element of array. For example, consider the array
6262
`[3, 0, 0, 2, 0, 4]`, We can trap "3*2 units" of water between 3 an 2, "1 unit"
6363
on top of bar 2 and "3 units" between 2 and 4. See below diagram also.
6464

65-
A **simple solution** is to traverse every array element and find the highest
66-
bars on left and right sides. Take the smaller of two heights. The difference
67-
between smaller height and height of current element is the amount of water
68-
that can be stored in this array element. Time complexity of this solution
69-
is `O(n2)`.
65+
### Approach 1: Brute force
7066

71-
An **efficient solution** is to pre-compute highest bar on left and right of
72-
every bar in `O(n)` time. Then use these pre-computed values to find the
73-
amount of water in every array element.
67+
**Intuition**
68+
69+
For each element in the array, we find the maximum level of water it can trap
70+
after the rain, which is equal to the minimum of maximum height of bars on both
71+
the sides minus its own height.
72+
73+
**Steps**
74+
75+
- Initialize `answer = 0`
76+
- Iterate the array from left to right:
77+
- Initialize `max_left = 0 and `max_right = 0`
78+
- Iterate from the current element to the beginning of array updating: `max_left = max(max_left, height[j])`
79+
- Iterate from the current element to the end of array updating: `max_right = max(max_right, height[j])`
80+
- Add `min(max_left, max_right) − height[i]` to `answer`
81+
82+
**Complexity Analysis**
83+
84+
Time complexity: `O(n^2)`. For each element of array, we iterate the left and right parts.
85+
86+
Auxiliary space complexity: `O(1)` extra space.
87+
88+
### Approach 2: Dynamic Programming
89+
90+
**Intuition**
91+
92+
In brute force, we iterate over the left and right parts again and again just to
93+
find the highest bar size up to that index. But, this could be stored. Voila,
94+
dynamic programming.
95+
96+
So we may pre-compute highest bar on left and right of every bar in `O(n)` time.
97+
Then use these pre-computed values to find the amount of water in every array element.
98+
99+
The concept is illustrated as shown:
100+
101+
![DP Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/Figures/42/trapping_rain_water.png)
102+
103+
**Steps**
104+
105+
- Find maximum height of bar from the left end up to an index `i` in the array `left_max`.
106+
- Find maximum height of bar from the right end up to an index `i` in the array `right_max`.
107+
- Iterate over the `height` array and update `answer`:
108+
- Add `min(max_left[i], max_right[i]) − height[i]` to `answer`.
109+
110+
**Complexity Analysis**
111+
112+
Time complexity: `O(n)`.
113+
114+
Auxiliary space complexity: `O(n)` extra space.
74115

75116
## References
76117

77118
- [GeeksForGeeks](https://www.geeksforgeeks.org/trapping-rain-water/)
119+
- [LeetCode](https://leetcode.com/problems/trapping-rain-water/solution/)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import bfRainTerraces from '../bfRainTerraces';
2+
3+
describe('bfRainTerraces', () => {
4+
it('should find the amount of water collected after raining', () => {
5+
expect(bfRainTerraces([1])).toBe(0);
6+
expect(bfRainTerraces([1, 0])).toBe(0);
7+
expect(bfRainTerraces([0, 1])).toBe(0);
8+
expect(bfRainTerraces([0, 1, 0])).toBe(0);
9+
expect(bfRainTerraces([0, 1, 0, 0])).toBe(0);
10+
expect(bfRainTerraces([0, 1, 0, 0, 1, 0])).toBe(2);
11+
expect(bfRainTerraces([0, 2, 0, 0, 1, 0])).toBe(2);
12+
expect(bfRainTerraces([2, 0, 2])).toBe(2);
13+
expect(bfRainTerraces([2, 0, 5])).toBe(2);
14+
expect(bfRainTerraces([3, 0, 0, 2, 0, 4])).toBe(10);
15+
expect(bfRainTerraces([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])).toBe(6);
16+
expect(bfRainTerraces([1, 1, 1, 1, 1])).toBe(0);
17+
expect(bfRainTerraces([1, 2, 3, 4, 5])).toBe(0);
18+
expect(bfRainTerraces([4, 1, 3, 1, 2, 1, 2, 1])).toBe(4);
19+
expect(bfRainTerraces([0, 2, 4, 3, 4, 2, 4, 0, 8, 7, 0])).toBe(7);
20+
});
21+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import dpRainTerraces from '../dpRainTerraces';
2+
3+
describe('dpRainTerraces', () => {
4+
it('should find the amount of water collected after raining', () => {
5+
expect(dpRainTerraces([1])).toBe(0);
6+
expect(dpRainTerraces([1, 0])).toBe(0);
7+
expect(dpRainTerraces([0, 1])).toBe(0);
8+
expect(dpRainTerraces([0, 1, 0])).toBe(0);
9+
expect(dpRainTerraces([0, 1, 0, 0])).toBe(0);
10+
expect(dpRainTerraces([0, 1, 0, 0, 1, 0])).toBe(2);
11+
expect(dpRainTerraces([0, 2, 0, 0, 1, 0])).toBe(2);
12+
expect(dpRainTerraces([2, 0, 2])).toBe(2);
13+
expect(dpRainTerraces([2, 0, 5])).toBe(2);
14+
expect(dpRainTerraces([3, 0, 0, 2, 0, 4])).toBe(10);
15+
expect(dpRainTerraces([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])).toBe(6);
16+
expect(dpRainTerraces([1, 1, 1, 1, 1])).toBe(0);
17+
expect(dpRainTerraces([1, 2, 3, 4, 5])).toBe(0);
18+
expect(dpRainTerraces([4, 1, 3, 1, 2, 1, 2, 1])).toBe(4);
19+
expect(dpRainTerraces([0, 2, 4, 3, 4, 2, 4, 0, 8, 7, 0])).toBe(7);
20+
});
21+
});

‎src/algorithms/uncategorized/rain-terraces/__test__/rainTerraces.test.js

-21
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* BRUTE FORCE approach of solving Trapping Rain Water problem.
3+
*
4+
* @param {number[]} terraces
5+
* @return {number}
6+
*/
7+
export default function bfRainTerraces(terraces) {
8+
let waterAmount = 0;
9+
10+
for (let terraceIndex = 0; terraceIndex < terraces.length; terraceIndex += 1) {
11+
// Get left most high terrace.
12+
let leftHighestLevel = 0;
13+
for (let leftIndex = terraceIndex - 1; leftIndex >= 0; leftIndex -= 1) {
14+
leftHighestLevel = Math.max(leftHighestLevel, terraces[leftIndex]);
15+
}
16+
17+
// Get right most high terrace.
18+
let rightHighestLevel = 0;
19+
for (let rightIndex = terraceIndex + 1; rightIndex < terraces.length; rightIndex += 1) {
20+
rightHighestLevel = Math.max(rightHighestLevel, terraces[rightIndex]);
21+
}
22+
23+
// Add current terrace water amount.
24+
const terraceBoundaryLevel = Math.min(leftHighestLevel, rightHighestLevel);
25+
if (terraceBoundaryLevel > terraces[terraceIndex]) {
26+
// Terrace will be able to store the water if the lowest of two left and right highest
27+
// terraces are still higher than the current one.
28+
waterAmount += Math.min(leftHighestLevel, rightHighestLevel) - terraces[terraceIndex];
29+
}
30+
}
31+
32+
return waterAmount;
33+
}

‎src/algorithms/uncategorized/rain-terraces/rainTerraces.js ‎src/algorithms/uncategorized/rain-terraces/dpRainTerraces.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/**
2+
* DYNAMIC PROGRAMMING approach of solving Trapping Rain Water problem.
3+
*
24
* @param {number[]} terraces
35
* @return {number}
46
*/
5-
export default function rainTerraces(terraces) {
7+
export default function dpRainTerraces(terraces) {
68
/*
79
* STEPS
810
*

0 commit comments

Comments
 (0)
Please sign in to comment.