From a97d9c380bbb0a0aee05cf92082b80449db4f293 Mon Sep 17 00:00:00 2001 From: EFanZh Date: Wed, 21 Aug 2024 21:42:42 +0800 Subject: [PATCH] Add problem 2025: Maximum Number of Ways to Partition an Array --- src/lib.rs | 1 + .../mod.rs | 43 +++++++ .../prefix_sum.rs | 109 ++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 src/problem_2025_maximum_number_of_ways_to_partition_an_array/mod.rs create mode 100644 src/problem_2025_maximum_number_of_ways_to_partition_an_array/prefix_sum.rs diff --git a/src/lib.rs b/src/lib.rs index 03b234a1..cef08b5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1499,6 +1499,7 @@ pub mod problem_2018_check_if_word_can_be_placed_in_crossword; pub mod problem_2022_convert_1d_array_into_2d_array; pub mod problem_2023_number_of_pairs_of_strings_with_concatenation_equal_to_target; pub mod problem_2024_maximize_the_confusion_of_an_exam; +pub mod problem_2025_maximum_number_of_ways_to_partition_an_array; pub mod problem_2027_minimum_moves_to_convert_string; pub mod problem_2028_find_missing_observations; pub mod problem_2029_stone_game_ix; diff --git a/src/problem_2025_maximum_number_of_ways_to_partition_an_array/mod.rs b/src/problem_2025_maximum_number_of_ways_to_partition_an_array/mod.rs new file mode 100644 index 00000000..e5c66ee7 --- /dev/null +++ b/src/problem_2025_maximum_number_of_ways_to_partition_an_array/mod.rs @@ -0,0 +1,43 @@ +pub mod prefix_sum; + +pub trait Solution { + fn ways_to_partition(nums: Vec, k: i32) -> i32; +} + +#[cfg(test)] +mod tests { + use super::Solution; + + pub fn run() { + let test_cases = [ + ((&[2, -1, 2] as &[_], 3), 1), + ((&[0, 0, 0], 1), 2), + ((&[22, 4, -25, -20, -15, 15, -16, 7, 19, -10, 0, -13, -14], -33), 4), + ( + ( + &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30827, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ], + 0, + ), + 33, + ), + ( + ( + &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, + 0, -99, 0, + ], + 0, + ), + 60, + ), + ]; + + for ((nums, k), expected) in test_cases { + assert_eq!(S::ways_to_partition(nums.to_vec(), k), expected); + } + } +} diff --git a/src/problem_2025_maximum_number_of_ways_to_partition_an_array/prefix_sum.rs b/src/problem_2025_maximum_number_of_ways_to_partition_an_array/prefix_sum.rs new file mode 100644 index 00000000..9504e65b --- /dev/null +++ b/src/problem_2025_maximum_number_of_ways_to_partition_an_array/prefix_sum.rs @@ -0,0 +1,109 @@ +pub struct Solution; + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +use std::collections::hash_map::{Entry, OccupiedEntry}; +use std::collections::HashMap; + +impl Solution { + fn unwrap_occupied(entry: Entry) -> OccupiedEntry { + match entry { + Entry::Occupied(entry) => entry, + Entry::Vacant(_) => unreachable!(), + } + } + + pub fn ways_to_partition(nums: Vec, k: i32) -> i32 { + let mut right_counts = HashMap::new(); + let mut sum = 0; + + for &num in &nums { + sum += num; + + match right_counts.entry(sum) { + Entry::Occupied(entry) => *entry.into_mut() += 1, + Entry::Vacant(entry) => { + entry.insert(1); + } + } + } + + let mut result = if sum % 2 == 0 { + right_counts.get(&(sum / 2)).copied().unwrap_or(0) - u32::from(sum == 0) + } else { + 0 + }; + + let mut left_counts = HashMap::new(); + let mut left_sum = 0; + + for &num in &nums { + left_sum += num; + + let right_count = Self::unwrap_occupied(right_counts.entry(left_sum)); + + if *right_count.get() == 1 { + right_count.remove(); + } else { + *right_count.into_mut() -= 1; + } + + let diff = k - num; + let new_sum = sum + diff; + + if new_sum % 2 == 0 { + let left_half = new_sum / 2; + let right_half = left_half - diff; + let mut score = u32::from(left_sum == right_half); + + if let Some(&left_count) = left_counts.get(&left_half) { + score += left_count; + } + + if let Some(&right_count) = right_counts.get(&right_half) { + score += right_count; + } + + result = result.max(score - u32::from(new_sum == 0)); + } + + match left_counts.entry(left_sum) { + Entry::Occupied(entry) => *entry.into_mut() += 1, + Entry::Vacant(entry) => { + entry.insert(1); + } + } + } + + result as _ + } +} + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +impl super::Solution for Solution { + fn ways_to_partition(nums: Vec, k: i32) -> i32 { + Self::ways_to_partition(nums, k) + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + #[test] + fn test_unwrap_occupied_success() { + super::Solution::unwrap_occupied(HashMap::from([(2, 3)]).entry(2)); + } + + #[test] + #[should_panic(expected = "internal error: entered unreachable code")] + fn test_unwrap_occupied_failure() { + super::Solution::unwrap_occupied(HashMap::from([(2, 5)]).entry(5)); + } + + #[test] + fn test_solution() { + super::super::tests::run::(); + } +}