Problem overview
A group has n friends, and when they meet, everybody shakes hands with everybody else once. The function count_hand_shakes returns how many handshakes happen.
For n = 3 with friends A, B and C, the handshakes are (A, B), (A, C) and (B, C), so the answer is 3.
Approach
You could simulate it: for each person, count the handshakes with the people who come after them, and add everything up. That works, but it needs a loop. A formula is shorter and faster.
Counting from one person's side
Each of the n people shakes hands with the other n - 1 people, which gives n * (n - 1) handshakes. But every handshake was counted twice: once from each of the two people involved. With three friends, the product is 3 * 2 = 6, and each of the three real handshakes shows up twice. Dividing by 2 corrects it.
The answer is n * (n - 1) / 2.
Counting a different way
Write out the handshakes for four friends, A to D, grouped by the first person:
(A, B) (A, C) (A, D)
(B, C) (B, D)
(C, D)
A starts 3 handshakes, B starts 2, C starts 1 and D starts none, for 3 + 2 + 1 = 6. Arranged as rows of dots this forms a staircase. Two copies of a staircase fit together into a rectangle with n - 1 rows and n columns, so the staircase holds half of (n - 1) * n. It is the same formula, and for n = 4 it gives 4 * 3 / 2 = 6.
Step by step
- Multiply
nbyn - 1. This counts each handshake from both sides. - Divide by 2 to count each handshake only once.
- Return the result.
The division is exact. Of any two consecutive numbers, n and n - 1, one is even, so their product is even and halving it leaves no remainder. That matters in Rust, where dividing two integers drops the fractional part.
The solution in Rust
impl Solution {
fn count_hand_shakes(n: i32) -> i32 {
return (n * (n - 1)) / 2;
}
}
The parentheses around n * (n - 1) are not required, since * and / have equal precedence and run left to right, but they make the intention clear. The division happens last, after the multiplication, which is what the formula needs: dividing n by 2 first would lose a fraction whenever n is odd.
Rust details
- Integer division. With
i32operands,/gives ani32. Here the product is always even, so nothing is lost. - Return. The line could also be written as the final expression
(n * (n - 1)) / 2, withoutreturnand without a semicolon.
Complexity
The function does one subtraction, one multiplication and one division regardless of n, so it takes O(1) time and O(1) space. A loop that adds up 1 + 2 + ... + (n - 1) would take O(n) time.
Edge cases and common mistakes
- One friend, or none. With
n = 1the formula gives 1 * 0 / 2 = 0, which is right: nobody to shake hands with. Forn = 0it computes 0 * (-1) / 2, which is also 0. - Two friends. One handshake: 2 * 1 / 2 = 1.
- Forgetting to halve.
n * (n - 1)alone counts every handshake twice. For n = 3 it returns 6 instead of 3. - Using n * n. That counts each person shaking hands with themselves as well.
- Overflow. The product is computed before the division, in
i32. Forn = 46341the product still fits and the function returns 1073720970. Forn = 46342the product goes past thei32limit, and in the optimized builds the lessons use it wraps silently, so the function returns -1073716337 instead of the true count, even though the true count itself fits in ani32. In a debug build the multiplication would panic instead. Normal test sizes stay below this limit.
Testing
count_hand_shakes(3)returns 3.count_hand_shakes(4)returns 6.count_hand_shakes(10)returns 45.count_hand_shakes(1)returns 0.
