Skip to content

Implement Trapped Rain Water Problem #712

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
* [Rod Cutting](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/rod_cutting.rs)
* [Snail](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/snail.rs)
* [Subset Generation](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/subset_generation.rs)
* [Trapped Rain Water](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/trapped_rainwater.rs)
* [Word Break](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/word_break.rs)
* General
* [Convex Hull](https://github.com/TheAlgorithms/Rust/blob/master/src/general/convex_hull.rs)
Expand Down
2 changes: 2 additions & 0 deletions src/dynamic_programming/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod minimum_cost_path;
mod rod_cutting;
mod snail;
mod subset_generation;
mod trapped_rainwater;
mod word_break;

pub use self::coin_change::coin_change;
Expand All @@ -41,4 +42,5 @@ pub use self::minimum_cost_path::minimum_cost_path;
pub use self::rod_cutting::rod_cut;
pub use self::snail::snail;
pub use self::subset_generation::list_subset;
pub use self::trapped_rainwater::trapped_rainwater;
pub use self::word_break::word_break;
125 changes: 125 additions & 0 deletions src/dynamic_programming/trapped_rainwater.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//! Module to calculate trapped rainwater in an elevation map.

/// Computes the total volume of trapped rainwater in a given elevation map.
///
/// # Arguments
///
/// * `elevation_map` - A slice containing the heights of the terrain elevations.
///
/// # Returns
///
/// The total volume of trapped rainwater.
pub fn trapped_rainwater(elevation_map: &[u32]) -> u32 {
let left_max = calculate_max_values(elevation_map, false);
let right_max = calculate_max_values(elevation_map, true);
let mut water_trapped = 0;
// Calculate trapped water
for i in 0..elevation_map.len() {
water_trapped += left_max[i].min(right_max[i]) - elevation_map[i];
}
water_trapped
}

/// Determines the maximum heights from either direction in the elevation map.
///
/// # Arguments
///
/// * `elevation_map` - A slice representing the heights of the terrain elevations.
/// * `reverse` - A boolean that indicates the direction of calculation.
/// - `false` for left-to-right.
/// - `true` for right-to-left.
///
/// # Returns
///
/// A vector containing the maximum heights encountered up to each position.
fn calculate_max_values(elevation_map: &[u32], reverse: bool) -> Vec<u32> {
let mut max_values = vec![0; elevation_map.len()];
let mut current_max = 0;
for i in create_iter(elevation_map.len(), reverse) {
current_max = current_max.max(elevation_map[i]);
max_values[i] = current_max;
}
max_values
}

/// Creates an iterator for the given length, optionally reversing it.
///
/// # Arguments
///
/// * `len` - The length of the iterator.
/// * `reverse` - A boolean that determines the order of iteration.
/// - `false` for forward iteration.
/// - `true` for reverse iteration.
///
/// # Returns
///
/// A boxed iterator that iterates over the range of indices.
fn create_iter(len: usize, reverse: bool) -> Box<dyn Iterator<Item = usize>> {
if reverse {
Box::new((0..len).rev())
} else {
Box::new(0..len)
}
}

#[cfg(test)]
mod tests {
use super::*;

macro_rules! trapped_rainwater_tests {
($($name:ident: $test_case:expr,)*) => {
$(
#[test]
fn $name() {
let (elevation_map, expected_trapped_water) = $test_case;
assert_eq!(trapped_rainwater(&elevation_map), expected_trapped_water);
let elevation_map_rev: Vec<u32> = elevation_map.iter().rev().cloned().collect();
assert_eq!(trapped_rainwater(&elevation_map_rev), expected_trapped_water);
}
)*
};
}

trapped_rainwater_tests! {
test_trapped_rainwater_basic: (
[0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1],
6
),
test_trapped_rainwater_peak_under_water: (
[3, 0, 2, 0, 4],
7,
),
test_bucket: (
[5, 1, 5],
4
),
test_skewed_bucket: (
[4, 1, 5],
3
),
test_trapped_rainwater_empty: (
[],
0
),
test_trapped_rainwater_flat: (
[0, 0, 0, 0, 0],
0
),
test_trapped_rainwater_no_trapped_water: (
[1, 1, 2, 4, 0, 0, 0],
0
),
test_trapped_rainwater_single_elevation_map: (
[5],
0
),
test_trapped_rainwater_two_point_elevation_map: (
[5, 1],
0
),
test_trapped_rainwater_large_elevation_map_difference: (
[5, 1, 6, 1, 7, 1, 8],
15
),
}
}