Problem overview
The method guestsMissing receives two lists of names: invited, whose names are all different, and arrived, the check-ins so far. It returns how many invited guests have not arrived. A guest may check in more than once, and still counts as one guest. Someone who was not invited may check in too, and that changes nothing.
With invited = ["Ava", "Leo", "Mia", "Zoe"] and arrived = ["Leo", "Zoe"], Ava and Mia are still missing, so the answer is 2. With invited = ["Ava", "Leo"] and arrived = ["Leo", "Max", "Leo"] the answer is 1: Leo checked in twice but is one guest, and Max was not invited.
Approach
Think of a list of missing guests. At first, everyone invited is missing. Each arrival crosses one name off. When all arrivals are processed, the names left are the guests who never came.
A set fits this well. Removing a name from a set that does not have it must be harmless, because both awkward cases need it: a repeated check-in removes a name that is already gone, and an uninvited guest removes a name that was never there. discard does exactly that.
Why not just compare lengths
It is tempting to subtract: invited guests minus arrivals. That only works if every arrival is a different invited guest, and the task says neither is guaranteed. A repeated check-in would be counted twice, and an uninvited guest would be counted as if someone invited had come. The answer depends on which names arrived, not how many arrivals there were, so the code has to work with the names themselves.
Starting from the invited names and crossing off the arrivals does that, and the final length counts only the invited guests who were never crossed off. Because the invited names are all different, set(invited) loses none of them.
Step by step
- Build
missing = set(invited). - Loop over
arrivedwithfor name in arrived. - Inside, call
missing.discard(name). - Return
len(missing).
The solution in Python
class Solution:
def guestsMissing(self, invited: List[str], arrived: List[str]) -> int:
missing = set(invited)
for name in arrived:
missing.discard(name)
return len(missing)
The key choice is discard over remove. remove raises KeyError when the name is not in the set, so the second "Leo" in the second example, or "Max", would crash the method.
Testing
| invited | arrived | result |
|---|---|---|
["Ava", "Leo", "Mia", "Zoe"] | ["Leo", "Zoe"] | 2 |
["Ava", "Leo"] | ["Leo", "Max", "Leo"] | 1 |
["Sam", "Kim"] | [] | 2 |
["Ava"] | ["Ava"] | 0 |
Why the set is the right tool
Every operation the loop needs is cheap on a set: building it, discarding a name, and counting what is left. The method makes one pass over each list, so its running time grows with the total number of names.
Edge cases and common mistakes
- Nobody arrived. The loop does not run and the answer is the number of invited guests.
- Everybody arrived. The set ends empty and the answer is 0.
- Counting arrivals instead.
len(invited) - len(arrived)goes wrong with repeats and uninvited guests: for the second example it gives 2 - 3 = -1. - Using
remove. It crashes on the first uninvited or repeated name. - Using a list for
missing.list.removealso raises an error (aValueError) for an absent value, and checking a list is slower than checking a set.
