From 3b56a71a141a142ec3be365f7080602df58b48e0 Mon Sep 17 00:00:00 2001 From: Truong Nhan Nguyen Date: Wed, 3 Jul 2024 19:55:15 +0700 Subject: [PATCH 1/3] ref: improve egg dropping implementation --- src/dynamic_programming/egg_dropping.rs | 147 +++++++++++------------- 1 file changed, 70 insertions(+), 77 deletions(-) diff --git a/src/dynamic_programming/egg_dropping.rs b/src/dynamic_programming/egg_dropping.rs index 624da98b5f7..41906bd4a78 100644 --- a/src/dynamic_programming/egg_dropping.rs +++ b/src/dynamic_programming/egg_dropping.rs @@ -1,91 +1,84 @@ -/// # Egg Dropping Puzzle +//! This module contains the `egg_drop` function, which determines the minimum number of egg droppings +//! required to find the highest floor from which an egg can be dropped without breaking. It also includes +//! tests for the function using various test cases, including edge cases. -/// `egg_drop(eggs, floors)` returns the least number of egg droppings -/// required to determine the highest floor from which an egg will not -/// break upon dropping +/// Returns the least number of egg droppings required to determine the highest floor from which an egg will not break upon dropping. /// -/// Assumptions: n > 0 -pub fn egg_drop(eggs: u32, floors: u32) -> u32 { - assert!(eggs > 0); - - // Explicity handle edge cases (optional) - if eggs == 1 || floors == 0 || floors == 1 { - return floors; - } - - let eggs_index = eggs as usize; - let floors_index = floors as usize; - - // Store solutions to subproblems in 2D Vec, - // where egg_drops[i][j] represents the solution to the egg dropping - // problem with i eggs and j floors - let mut egg_drops: Vec> = vec![vec![0; floors_index + 1]; eggs_index + 1]; - - // Assign solutions for egg_drop(n, 0) = 0, egg_drop(n, 1) = 1 - for egg_drop in egg_drops.iter_mut().skip(1) { - egg_drop[0] = 0; - egg_drop[1] = 1; - } - - // Assign solutions to egg_drop(1, k) = k - for j in 1..=floors_index { - egg_drops[1][j] = j as u32; +/// # Arguments +/// +/// * `eggs` - The number of eggs available. +/// * `floors` - The number of floors in the building. +/// +/// # Returns +/// +/// * `Some(usize)` - The minimum number of drops required if the number of eggs is greater than 0. +/// * `None` - If the number of eggs is less than or equal to 0. +pub fn egg_drop(eggs: usize, floors: usize) -> Option { + if eggs == 0 { + return None; } - // Complete solutions vector using optimal substructure property - for i in 2..=eggs_index { - for j in 2..=floors_index { - egg_drops[i][j] = u32::MAX; - - for k in 1..=j { - let res = 1 + std::cmp::max(egg_drops[i - 1][k - 1], egg_drops[i][j - k]); - - if res < egg_drops[i][j] { - egg_drops[i][j] = res; - } - } - } + if eggs == 1 || floors == 0 || floors == 1 { + return Some(floors); } - egg_drops[eggs_index][floors_index] + // Create a 2D vector to store solutions to subproblems + let mut egg_drops: Vec> = vec![vec![0; floors + 1]; eggs + 1]; + + // Base cases: 0 floors -> 0 drops, 1 floor -> 1 drop + (1..=eggs).for_each(|i| { + egg_drops[i][1] = 1; + }); + + // Base case: 1 egg -> k drops for k floors + (1..=floors).for_each(|j| { + egg_drops[1][j] = j; + }); + + // Fill the table using the optimal substructure property + (2..=eggs).for_each(|i| { + (2..=floors).for_each(|j| { + egg_drops[i][j] = (1..=j) + .map(|k| 1 + std::cmp::max(egg_drops[i - 1][k - 1], egg_drops[i][j - k])) + .min() + .unwrap(); + }); + }); + + Some(egg_drops[eggs][floors]) } #[cfg(test)] mod tests { - use super::egg_drop; - - #[test] - fn zero_floors() { - assert_eq!(egg_drop(5, 0), 0); - } - - #[test] - fn one_egg() { - assert_eq!(egg_drop(1, 8), 8); - } - - #[test] - fn eggs2_floors2() { - assert_eq!(egg_drop(2, 2), 2); - } - - #[test] - fn eggs3_floors5() { - assert_eq!(egg_drop(3, 5), 3); - } - - #[test] - fn eggs2_floors10() { - assert_eq!(egg_drop(2, 10), 4); - } - - #[test] - fn eggs2_floors36() { - assert_eq!(egg_drop(2, 36), 8); + use super::*; + + macro_rules! egg_drop_tests { + ($($name:ident: $test_cases:expr,)*) => { + $( + #[test] + fn $name() { + let (eggs, floors, expected) = $test_cases; + assert_eq!(egg_drop(eggs, floors), expected); + } + )* + } } - #[test] - fn large_floors() { - assert_eq!(egg_drop(2, 100), 14); + egg_drop_tests! { + test_no_floors: (5, 0, Some(0)), + test_one_egg_multiple_floors: (1, 8, Some(8)), + test_multiple_eggs_one_floor: (5, 1, Some(1)), + test_two_eggs_two_floors: (2, 2, Some(2)), + test_three_eggs_five_floors: (3, 5, Some(3)), + test_two_eggs_ten_floors: (2, 10, Some(4)), + test_two_eggs_thirty_six_floors: (2, 36, Some(8)), + test_many_eggs_one_floor: (100, 1, Some(1)), + test_many_eggs_few_floors: (100, 5, Some(3)), + test_few_eggs_many_floors: (2, 1000, Some(45)), + test_zero_eggs: (0, 10, None::), + test_no_eggs_no_floors: (0, 0, None::), + test_one_egg_no_floors: (1, 0, Some(0)), + test_one_egg_one_floor: (1, 1, Some(1)), + test_maximum_floors_one_egg: (1, usize::MAX, Some(usize::MAX)), } } From 942e5a5be4a7518e3f1de419318b8f45e3839c63 Mon Sep 17 00:00:00 2001 From: Truong Nhan Nguyen Date: Mon, 19 Aug 2024 20:24:31 +0700 Subject: [PATCH 2/3] chore: update docstring --- src/dynamic_programming/egg_dropping.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dynamic_programming/egg_dropping.rs b/src/dynamic_programming/egg_dropping.rs index 41906bd4a78..006bdd8a1ca 100644 --- a/src/dynamic_programming/egg_dropping.rs +++ b/src/dynamic_programming/egg_dropping.rs @@ -12,7 +12,7 @@ /// # Returns /// /// * `Some(usize)` - The minimum number of drops required if the number of eggs is greater than 0. -/// * `None` - If the number of eggs is less than or equal to 0. +/// * `None` - If the number of eggs 0. pub fn egg_drop(eggs: usize, floors: usize) -> Option { if eggs == 0 { return None; From a888afad4cb8db66f2874d561da6bfc9b3af7c86 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:47:05 +0200 Subject: [PATCH 3/3] style: use proper grammar --- src/dynamic_programming/egg_dropping.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dynamic_programming/egg_dropping.rs b/src/dynamic_programming/egg_dropping.rs index 006bdd8a1ca..ab24494c014 100644 --- a/src/dynamic_programming/egg_dropping.rs +++ b/src/dynamic_programming/egg_dropping.rs @@ -12,7 +12,7 @@ /// # Returns /// /// * `Some(usize)` - The minimum number of drops required if the number of eggs is greater than 0. -/// * `None` - If the number of eggs 0. +/// * `None` - If the number of eggs is 0. pub fn egg_drop(eggs: usize, floors: usize) -> Option { if eggs == 0 { return None;