From 71f59bd0a984f050cf2f478f1d918c90950ff679 Mon Sep 17 00:00:00 2001 From: EFanZh Date: Mon, 1 Jan 2024 14:03:30 +0800 Subject: [PATCH] Add problem 1733: Minimum Number of People to Teach --- src/lib.rs | 1 + .../bit_set.rs | 100 ++++++++++++++++++ .../hash_set.rs | 69 ++++++++++++ .../mod.rs | 43 ++++++++ 4 files changed, 213 insertions(+) create mode 100644 src/problem_1733_minimum_number_of_people_to_teach/bit_set.rs create mode 100644 src/problem_1733_minimum_number_of_people_to_teach/hash_set.rs create mode 100644 src/problem_1733_minimum_number_of_people_to_teach/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 2d507b31..a6d1933e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1293,6 +1293,7 @@ pub mod problem_1725_number_of_rectangles_that_can_form_the_largest_square; pub mod problem_1726_tuple_with_same_product; pub mod problem_1727_largest_submatrix_with_rearrangements; pub mod problem_1732_find_the_highest_altitude; +pub mod problem_1733_minimum_number_of_people_to_teach; pub mod problem_1734_decode_xored_permutation; pub mod problem_1736_latest_time_by_replacing_hidden_digits; pub mod problem_1737_change_minimum_characters_to_satisfy_one_of_three_conditions; diff --git a/src/problem_1733_minimum_number_of_people_to_teach/bit_set.rs b/src/problem_1733_minimum_number_of_people_to_teach/bit_set.rs new file mode 100644 index 00000000..0e140365 --- /dev/null +++ b/src/problem_1733_minimum_number_of_people_to_teach/bit_set.rs @@ -0,0 +1,100 @@ +pub struct Solution; + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +use std::convert::TryInto; + +struct BitSet { + data: [u64; 8], +} + +impl BitSet { + fn new(data: Vec) -> Self { + let mut inner_data = [0_u64; 8]; + + for x in data { + let x = x as u32; + let index = x / 64; + let bit = x % 64; + + inner_data[index as usize] |= 1 << bit; + } + + Self { data: inner_data } + } + + fn has_common_bit(&self, other: &Self) -> bool { + self.data.iter().zip(&other.data).any(|(lhs, rhs)| (lhs & rhs) != 0) + } + + fn bits(&self, mut f: impl FnMut(u32)) { + let mut start = 0; + + for &bits in &self.data { + let mut bits = bits; + + while bits != 0 { + f(start + bits.trailing_zeros()); + + bits &= bits - 1; + } + + start += 64; + } + } +} + +impl Solution { + pub fn minimum_teachings(n: i32, languages: Vec>, friendships: Vec>) -> i32 { + let languages = languages.into_iter().map(BitSet::new).collect::>(); + + let mut need_to_learn = vec![false; languages.len()].into_boxed_slice(); + let mut language_counts = vec![0_u16; n as u32 as usize].into_boxed_slice(); + let mut total = 0; + let mut max_common_languages = 0; + + for friendship in friendships { + let [x, y]: [_; 2] = friendship.try_into().ok().unwrap(); + let x = x as u32 as usize - 1; + let y = y as u32 as usize - 1; + let x_languages = &languages[x]; + let y_languages = &languages[y]; + + if !x_languages.has_common_bit(y_languages) { + for (i, languages) in [(x, x_languages), (y, y_languages)] { + if let state @ false = &mut need_to_learn[i] { + *state = true; + + total += 1; + + languages.bits(|language| { + let count = &mut language_counts[language as usize - 1]; + + *count += 1; + + max_common_languages = max_common_languages.max(*count); + }); + } + } + } + } + + i32::from(total - max_common_languages) + } +} + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +impl super::Solution for Solution { + fn minimum_teachings(n: i32, languages: Vec>, friendships: Vec>) -> i32 { + Self::minimum_teachings(n, languages, friendships) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_solution() { + super::super::tests::run::(); + } +} diff --git a/src/problem_1733_minimum_number_of_people_to_teach/hash_set.rs b/src/problem_1733_minimum_number_of_people_to_teach/hash_set.rs new file mode 100644 index 00000000..c36e17f5 --- /dev/null +++ b/src/problem_1733_minimum_number_of_people_to_teach/hash_set.rs @@ -0,0 +1,69 @@ +pub struct Solution; + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +use std::collections::HashSet; +use std::convert::TryInto; + +impl Solution { + pub fn minimum_teachings(n: i32, languages: Vec>, friendships: Vec>) -> i32 { + let languages = languages + .into_iter() + .map(|languages| { + languages + .into_iter() + .map(|language| language as u16 - 1) + .collect::>() + }) + .collect::>(); + + let mut need_to_learn = vec![false; languages.len()].into_boxed_slice(); + let mut language_counts = vec![0_u16; n as u32 as usize].into_boxed_slice(); + let mut total = 0; + let mut max_common_languages = 0; + + for friendship in friendships { + let [x, y]: [_; 2] = friendship.try_into().ok().unwrap(); + let x = x as u32 as usize - 1; + let y = y as u32 as usize - 1; + let x_languages = &languages[x]; + let y_languages = &languages[y]; + + if x_languages.intersection(y_languages).next().is_none() { + for (i, languages) in [(x, x_languages), (y, y_languages)] { + if let state @ false = &mut need_to_learn[i] { + *state = true; + + total += 1; + + for &language in languages { + let count = &mut language_counts[usize::from(language)]; + + *count += 1; + + max_common_languages = max_common_languages.max(*count); + } + } + } + } + } + + i32::from(total - max_common_languages) + } +} + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +impl super::Solution for Solution { + fn minimum_teachings(n: i32, languages: Vec>, friendships: Vec>) -> i32 { + Self::minimum_teachings(n, languages, friendships) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_solution() { + super::super::tests::run::(); + } +} diff --git a/src/problem_1733_minimum_number_of_people_to_teach/mod.rs b/src/problem_1733_minimum_number_of_people_to_teach/mod.rs new file mode 100644 index 00000000..495f6fd4 --- /dev/null +++ b/src/problem_1733_minimum_number_of_people_to_teach/mod.rs @@ -0,0 +1,43 @@ +pub mod bit_set; +pub mod hash_set; + +pub trait Solution { + fn minimum_teachings(n: i32, languages: Vec>, friendships: Vec>) -> i32; +} + +#[cfg(test)] +mod tests { + use super::Solution; + + pub fn run() { + let test_cases = [ + ( + ( + 2, + &[&[1] as &[_], &[2], &[1, 2]] as &[&[_]], + &[&[1, 2] as &[_], &[1, 3], &[2, 3]] as &[&[_]], + ), + 1, + ), + ( + ( + 3, + &[&[2], &[1, 3], &[1, 2], &[3]], + &[&[1, 4], &[1, 2], &[3, 4], &[2, 3]], + ), + 2, + ), + ]; + + for ((n, languages, friendships), expected) in test_cases { + assert_eq!( + S::minimum_teachings( + n, + languages.iter().copied().map(<[_]>::to_vec).collect(), + friendships.iter().copied().map(<[_]>::to_vec).collect(), + ), + expected, + ); + } + } +}