Dynamic Programming · 47 of 60
Count Derangements (Permutation such that no element appears in its original position)
Count the ways to hand back the hats at a party so that nobody gets their own hat.
- Simple way
- time O(2^n)
room O(n) - Clever way
- time O(n)
room O(1)
The problem, simply
You have n things in a row, each in its own spot. Shuffle them so that no thing stays in its own spot. Count how many such shuffles exist. A shuffle like that is called a derangement.
The count gets huge, so judges want it modulo 10^9 + 7.
A story to remember it
Picture it
Top row: four kids. Bottom row: their own hats (A owns a, and so on). The solid lines are one good shuffle: A gets b, B gets a, C gets d, D gets c. Nobody is matched to the hat right below them.
- looking now
- answer
Examples
Three kids
- In
n = 3- Out
2
With kids 1, 2, 3, the good shuffles are (2, 3, 1) and (3, 1, 2). Every other order leaves someone with their own hat.
Four kids
- In
n = 4- Out
9
3 x (D(3) + D(2)) = 3 x (2 + 1) = 9.
One kid
- In
n = 1- Out
0
The only hat left is their own. No good shuffle exists.
Two kids
- In
n = 2- Out
1
They swap. That is the only way.
Six kids
- In
n = 6- Out
265
Out of 720 orders, 265 leave nobody with their own hat. That is about 720 / e.
Way 1: the simple way
The most obvious try is to list all n! orders and check each one. That is far too slow even for n = 12. The story gives a much better rule, so start from that with plain recursion:
D(1) = 0andD(2) = 1.- For bigger
n:D(n) = (n - 1) * (D(n - 1) + D(n - 2)).
D(5) asks D(4) and D(3). D(4) asks D(3) again. Faded circles are answers already worked out once. Double rings are the small cases we just know: D(1) = 0 and D(2) = 1.
- seen
class Solution {
static final long MOD = 1_000_000_007L;
long D(int n) {
if (n == 1) return 0; // your own hat is the only one left
if (n == 2) return 1; // swap
// first kid picks one of n-1 hats; then swap (n-2 left) or no swap (n-1 left)
return (n - 1) * ((D(n - 1) + D(n - 2)) % MOD) % MOD;
}
public long countDer(int n) {
return D(n);
}
}How long it takes: each call makes two calls, like Fibonacci, so the calls grow up to O(2^n). Extra room: the chain of waiting calls, O(n).
Way 2: the clever way
The two cases from the story, drawn for four kids:
Case 1: A takes B's hat and B takes A's hat. They just swap. C and D must now shuffle on their own: that is D(n - 2).
- checking
- done
- answer
Case 2: A takes B's hat, but B must not take A's hat. Pretend hat a belongs to B. Now B, C and D each have one hat they must not take: that is D(n - 1).
- checking
- done
- answer
- rejected
The recursion keeps working out the same D(3). Fill the answers from small to big instead. Each one only needs the two before it, so keep two numbers.
- Start with
prev2 = D(1) = 0andprev1 = D(2) = 1. - For
ifrom 3 ton:cur = (i - 1) * (prev1 + prev2), then slide:prev2 = prev1,prev1 = cur. - Return
prev1(or 0 whenn == 1).
Fill D(n) from the two answers before it
01 / 07
Box i holds D(i), the number of good shuffles for i kids. One kid alone must take their own hat, so D(1) = 0.
- checking
- answer
- just added
class Solution {
public long countDer(int n) {
final long MOD = 1_000_000_007L;
if (n == 1) return 0;
if (n == 2) return 1;
long prev2 = 0; // D(1)
long prev1 = 1; // D(2)
for (int i = 3; i <= n; i++) {
long cur = (i - 1) * ((prev1 + prev2) % MOD) % MOD;
prev2 = prev1; // slide the window forward
prev1 = cur;
}
return prev1;
}
}How long it takes: one step per kid, O(n). Extra room: two numbers, O(1).
Watch out for
D(1) = 0, not 1. And if the judge definesD(0), it is 1 (the empty shuffle).- Take the modulo inside:
(i - 1) * (prev1 + prev2)can overflow alongifprev1 + prev2is not reduced first. - Return
prev1, notcur. Whennis 1 or 2 the loop never runs.
What interviewers ask next
- Is there another rule? Yes:
D(n) = n * D(n - 1) + (-1)^n. It needs only one earlier value. - What fraction of all shuffles are derangements? It quickly gets close to
1/e, about 0.368. In factD(n)isn! / erounded to the nearest whole number. Quant interviews love this one: "n people grab random hats, what is the chance nobody gets their own?" - Exactly
kpeople get their own hat? Choose who they are, then derange the rest:C(n, k) * D(n - k). - Expected number of people who get their own hat? Exactly 1 for any
n, because each person has a1/nchance and there arenpeople. - Where does the formula come from without the story? Inclusion and exclusion:
D(n) = n! * (1 - 1/1! + 1/2! - ... + (-1)^n / n!).
Remember this
Grown-up words: a shuffle with nobody in their own spot is a derangement, a shuffle is a permutation, the two cases are a case split for a recurrence, and keeping two numbers is space optimization.