Problem overview
The method countHandShakes receives n, the number of friends in a group, and returns how many handshakes happen when everybody shakes hands with everybody else. Each pair of friends shakes hands once.
With n = 3 and friends A, B and C, the handshakes are (A, B), (A, C) and (B, C), so the answer is 3. With four friends A, B, C and D there are six: (A, B), (A, C), (A, D), (B, C), (B, D) and (C, D).
Approach: count pairs, not people
You could simulate the meeting with two nested loops, one handshake at a time. That works, but it takes time proportional to n squared, and the pattern behind it gives a direct formula.
List the handshakes by who starts them. For four friends, A shakes hands with 3 others (B, C, D). B has already shaken A's hand, so B adds 2 more. C adds 1, and D adds none. The total is 3 + 2 + 1 = 6. In general the answer is (n - 1) + (n - 2) + ... + 1.
There is a shorter way to see the same sum. Every one of the n people shakes hands with the other n - 1 people, which makes n * (n - 1) handshakes if you count from each person's side. But each handshake involves two people, so it was counted twice, once from each side. Halving gives the number of distinct handshakes:
n * (n - 1) / 2
For n = 4 that is 4 * 3 / 2 = 6, and for n = 3 it is 3 * 2 / 2 = 3.
Step by step
- Take the number of people who can be shaken hands with. Each person has
n - 1possible partners, since nobody shakes their own hand. - Multiply by the number of people.
n * (n - 1)counts every handshake from both sides. - Divide by 2 so that each handshake counts once.
- Return the result. The method needs a single
returnstatement.
The solution in TypeScript
class Solution {
countHandShakes(n: number): number {
return (n * (n - 1)) / 2;
}
}
Some details worth knowing:
- The division is safe. In TypeScript,
/on numbers keeps the fraction (7 / 2is 3.5), so you might expect to needMath.floor. Here you don't, because of a fact about whole numbers:nandn - 1are consecutive, so one of them is even, and their product is always even. Dividing by 2 leaves no remainder. - Types are erased. The annotation
n: numberdocuments the intent and lets the compiler check callers, but it does nothing at run time. If a caller gets around the type checker and passes a non-integer such as3.5, the method returns4.375instead of failing. - One number type. Every TypeScript
numberis a double, so there is no integer overflow. The productn * (n - 1)is exact as long as it stays below 2^53, which holds for roughly 94 million friends or fewer. - Methods on a class. The lesson wraps the logic in a
Solutionclass. The method is called on an instance, as innew Solution().countHandShakes(4).
Complexity
Time: O(1). The method does one multiplication, one subtraction and one division, no matter how large n is.
Space: O(1). It stores no extra data.
Edge cases and common mistakes
- Forgetting to halve.
n * (n - 1)gives 12 for four friends instead of 6. - Using
n * n / 2. That counts handshakes with yourself as well. Forn = 4it gives 8. - Precedence. Writing
n * n - 1 / 2divides only the 1. Keep the parentheses aroundn - 1. - One person or none.
n = 1gives 0, which is right: nobody to shake hands with.n = 0also returns zero, though JavaScript prints it as-0, because0 * -1is negative zero. It still compares equal to 0 with===. - Two people.
n = 2gives exactly 1 handshake.
Testing
n = 2gives1.n = 3gives3.n = 4gives6.n = 10gives45.n = 100000gives4999950000.