Start learning free

LESSON 242 OF 679 · SETS

Guest Check-In in Rust: Counting Missing Guests With a HashSet

Practice Read the full explanation

You get two Vecs of names, invited and arrived. Return how many invited guests haven't arrived yet.

A guest may check in more than once. They still count as one guest.

Someone who wasn't invited may check in too. They don't change the answer.

 

Example 1:

Input: invited = ["Ava", "Leo", "Mia", "Zoe"], arrived = ["Leo", "Zoe"]
Output: 2
Explanation: Leo and Zoe are here.
Ava and Mia haven't arrived yet.

Example 2:

Input: invited = ["Ava", "Leo"], arrived = ["Leo", "Max", "Leo"]
Output: 1
Explanation: Leo checked in twice, but he is one guest.
Max wasn't invited.
Only Ava is missing.

Example 3:

Input: invited = ["Sam", "Kim"], arrived = []
Output: 2
Explanation: Nobody has arrived yet.

 

Constraints:

  • invited has 1 to 100 names.
  • arrived has 0 to 100 names.
  • The names in invited are all different.
  • Each name is one word of English letters, starting with a capital letter.
STEP 1 OF 4
    Ctrl + Enter to check

    RUST · SETS

    Guest Check In in Rust, explained

    Problem overview

    The function guests_missing receives two vectors of names, invited and arrived, and returns how many invited guests haven't arrived yet. Two details shape the answer:

    • A guest may check in more than once, but still counts as one guest.
    • Someone who wasn't invited may check in, and that must not change the answer.

    For invited = ["Ava", "Leo", "Mia", "Zoe"] and arrived = ["Leo", "Zoe"] the answer is 2 (Ava and Mia). For invited = ["Ava", "Leo"] and arrived = ["Leo", "Max", "Leo"] the answer is 1: Leo checked in twice, Max wasn't invited, only Ava is missing.

    Approach

    Start by assuming every invited guest is missing, then cross names off as people arrive. A HashSet fits: it holds each name once and removing a name that isn't in it does nothing. That one behaviour handles both tricky cases. A second check-in finds the name already gone, and an uninvited guest was never in the set. When the arrivals are done, whatever is left in the set is the answer.

    Step by step

    1. Build the set missing from invited with into_iter().collect(). It must be let mut, because names will be removed.
    2. Loop over &arrived. Each name is a reference to a String.
    3. Call missing.remove(name). Since name already is a reference, that is exactly what remove wants.
    4. After the loop, return missing.len(). A length is a usize, so convert it with as i32 to match the return type.

    The solution in Rust

    impl Solution {
        fn guests_missing(invited: Vec<String>, arrived: Vec<String>) -> i32 {
            let mut missing: HashSet<String> = invited.into_iter().collect();
            for name in &arrived {
                missing.remove(name);
            }
            return missing.len() as i32;
        }
    }
    

    The result of remove (a bool) is simply ignored; the loop only cares about the effect.

    Trying it

    Running the function gives:

    invited = [Ava, Leo, Mia, Zoe], arrived = [Leo, Zoe]       ->  2
    invited = [Ava, Leo], arrived = [Leo, Max, Leo]            ->  1
    invited = [Sam, Kim], arrived = []                         ->  2
    invited = [Sam], arrived = [Sam, Sam]                      ->  0
    

    The third line is the case of an empty arrived: the loop never runs, so every invited guest is still missing. In the last line the second Sam removes nothing, and the answer stays 0 instead of going negative.

    Why a set and not a vector

    The same idea works with a vector: look up each arrival in invited and mark it. But a vector's contains and remove must scan from the start, and removing from the middle shifts every later element. A set finds a name directly, and removing a name that isn't there is not an error. That is why the loop in the solution has no if at all: the set absorbs the repeats and the uninvited names by itself.

    The names in invited are all different, so building the set loses nothing. If the list could repeat a name, the set would count that guest once, which is also what a head count of guests should do.

    Common mistakes

    • Subtracting lengths. invited.len() - arrived.len() counts check-ins, not guests: repeats and uninvited people throw it off. With ["Ava", "Leo"] and ["Leo", "Max", "Leo"] the difference is negative, and since lengths are usize, it wraps to a huge number in an optimized build instead of giving -1.
    • Counting inside the loop. Adding 1 per arrival counts repeats; the set does the de-duplication for you.
    • Forgetting mut. A set declared with plain let can't have names removed.
    • Returning missing.len() without the cast. The function returns i32, and Rust does not convert usize to i32 by itself.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free