Skip to content

Commit bb1a83c

Browse files
sozelfistvil02
andcommitted
Implement Trapped Rain Water Problem (#712)
* chore: add `trapped_rainwater.rs` to DIRECTORY.md * feat: implement Trapped Rain Water algorithm * chore: add tests * chore: rename `height` to `elevation_map` * ref: change `Vec<u32` to `[u32]` * ref: refactor implementation - Create iterator in a single function - Add tests - Rewrite docstring * tests: add more test cases * style: simplify logic by removing redundant branch --------- Co-authored-by: Piotr Idzik <[email protected]>
1 parent 8674596 commit bb1a83c

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
* [Rod Cutting](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/rod_cutting.rs)
9494
* [Snail](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/snail.rs)
9595
* [Subset Generation](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/subset_generation.rs)
96+
* [Trapped Rain Water](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/trapped_rainwater.rs)
9697
* [Word Break](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/word_break.rs)
9798
* General
9899
* [Convex Hull](https://github.com/TheAlgorithms/Rust/blob/master/src/general/convex_hull.rs)

src/dynamic_programming/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod minimum_cost_path;
1515
mod rod_cutting;
1616
mod snail;
1717
mod subset_generation;
18+
mod trapped_rainwater;
1819
mod word_break;
1920

2021
pub use self::coin_change::coin_change;
@@ -41,4 +42,5 @@ pub use self::minimum_cost_path::minimum_cost_path;
4142
pub use self::rod_cutting::rod_cut;
4243
pub use self::snail::snail;
4344
pub use self::subset_generation::list_subset;
45+
pub use self::trapped_rainwater::trapped_rainwater;
4446
pub use self::word_break::word_break;
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//! Module to calculate trapped rainwater in an elevation map.
2+
3+
/// Computes the total volume of trapped rainwater in a given elevation map.
4+
///
5+
/// # Arguments
6+
///
7+
/// * `elevation_map` - A slice containing the heights of the terrain elevations.
8+
///
9+
/// # Returns
10+
///
11+
/// The total volume of trapped rainwater.
12+
pub fn trapped_rainwater(elevation_map: &[u32]) -> u32 {
13+
let left_max = calculate_max_values(elevation_map, false);
14+
let right_max = calculate_max_values(elevation_map, true);
15+
let mut water_trapped = 0;
16+
// Calculate trapped water
17+
for i in 0..elevation_map.len() {
18+
water_trapped += left_max[i].min(right_max[i]) - elevation_map[i];
19+
}
20+
water_trapped
21+
}
22+
23+
/// Determines the maximum heights from either direction in the elevation map.
24+
///
25+
/// # Arguments
26+
///
27+
/// * `elevation_map` - A slice representing the heights of the terrain elevations.
28+
/// * `reverse` - A boolean that indicates the direction of calculation.
29+
/// - `false` for left-to-right.
30+
/// - `true` for right-to-left.
31+
///
32+
/// # Returns
33+
///
34+
/// A vector containing the maximum heights encountered up to each position.
35+
fn calculate_max_values(elevation_map: &[u32], reverse: bool) -> Vec<u32> {
36+
let mut max_values = vec![0; elevation_map.len()];
37+
let mut current_max = 0;
38+
for i in create_iter(elevation_map.len(), reverse) {
39+
current_max = current_max.max(elevation_map[i]);
40+
max_values[i] = current_max;
41+
}
42+
max_values
43+
}
44+
45+
/// Creates an iterator for the given length, optionally reversing it.
46+
///
47+
/// # Arguments
48+
///
49+
/// * `len` - The length of the iterator.
50+
/// * `reverse` - A boolean that determines the order of iteration.
51+
/// - `false` for forward iteration.
52+
/// - `true` for reverse iteration.
53+
///
54+
/// # Returns
55+
///
56+
/// A boxed iterator that iterates over the range of indices.
57+
fn create_iter(len: usize, reverse: bool) -> Box<dyn Iterator<Item = usize>> {
58+
if reverse {
59+
Box::new((0..len).rev())
60+
} else {
61+
Box::new(0..len)
62+
}
63+
}
64+
65+
#[cfg(test)]
66+
mod tests {
67+
use super::*;
68+
69+
macro_rules! trapped_rainwater_tests {
70+
($($name:ident: $test_case:expr,)*) => {
71+
$(
72+
#[test]
73+
fn $name() {
74+
let (elevation_map, expected_trapped_water) = $test_case;
75+
assert_eq!(trapped_rainwater(&elevation_map), expected_trapped_water);
76+
let elevation_map_rev: Vec<u32> = elevation_map.iter().rev().cloned().collect();
77+
assert_eq!(trapped_rainwater(&elevation_map_rev), expected_trapped_water);
78+
}
79+
)*
80+
};
81+
}
82+
83+
trapped_rainwater_tests! {
84+
test_trapped_rainwater_basic: (
85+
[0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1],
86+
6
87+
),
88+
test_trapped_rainwater_peak_under_water: (
89+
[3, 0, 2, 0, 4],
90+
7,
91+
),
92+
test_bucket: (
93+
[5, 1, 5],
94+
4
95+
),
96+
test_skewed_bucket: (
97+
[4, 1, 5],
98+
3
99+
),
100+
test_trapped_rainwater_empty: (
101+
[],
102+
0
103+
),
104+
test_trapped_rainwater_flat: (
105+
[0, 0, 0, 0, 0],
106+
0
107+
),
108+
test_trapped_rainwater_no_trapped_water: (
109+
[1, 1, 2, 4, 0, 0, 0],
110+
0
111+
),
112+
test_trapped_rainwater_single_elevation_map: (
113+
[5],
114+
0
115+
),
116+
test_trapped_rainwater_two_point_elevation_map: (
117+
[5, 1],
118+
0
119+
),
120+
test_trapped_rainwater_large_elevation_map_difference: (
121+
[5, 1, 6, 1, 7, 1, 8],
122+
15
123+
),
124+
}
125+
}

0 commit comments

Comments
 (0)