Skip to content

Commit

Permalink
Add problem 1733: Minimum Number of People to Teach
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed Jan 1, 2024
1 parent 14eefae commit 71f59bd
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
100 changes: 100 additions & 0 deletions src/problem_1733_minimum_number_of_people_to_teach/bit_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
pub struct Solution;

// ------------------------------------------------------ snip ------------------------------------------------------ //

use std::convert::TryInto;

struct BitSet {
data: [u64; 8],
}

impl BitSet {
fn new(data: Vec<i32>) -> 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<Vec<i32>>, friendships: Vec<Vec<i32>>) -> i32 {
let languages = languages.into_iter().map(BitSet::new).collect::<Box<_>>();

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<Vec<i32>>, friendships: Vec<Vec<i32>>) -> i32 {
Self::minimum_teachings(n, languages, friendships)
}
}

#[cfg(test)]
mod tests {
#[test]
fn test_solution() {
super::super::tests::run::<super::Solution>();
}
}
69 changes: 69 additions & 0 deletions src/problem_1733_minimum_number_of_people_to_teach/hash_set.rs
Original file line number Diff line number Diff line change
@@ -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<Vec<i32>>, friendships: Vec<Vec<i32>>) -> i32 {
let languages = languages
.into_iter()
.map(|languages| {
languages
.into_iter()
.map(|language| language as u16 - 1)
.collect::<HashSet<_>>()
})
.collect::<Box<_>>();

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<Vec<i32>>, friendships: Vec<Vec<i32>>) -> i32 {
Self::minimum_teachings(n, languages, friendships)
}
}

#[cfg(test)]
mod tests {
#[test]
fn test_solution() {
super::super::tests::run::<super::Solution>();
}
}
43 changes: 43 additions & 0 deletions src/problem_1733_minimum_number_of_people_to_teach/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pub mod bit_set;
pub mod hash_set;

pub trait Solution {
fn minimum_teachings(n: i32, languages: Vec<Vec<i32>>, friendships: Vec<Vec<i32>>) -> i32;
}

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

pub fn run<S: Solution>() {
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,
);
}
}
}

0 comments on commit 71f59bd

Please sign in to comment.