Counting Derangements
Tags: Programming, Coding, Software Engineering Job, Interview Questions, Dynamic Programming

Hey everyone here is the easiest explanation of problem of counting derangements. So what is a derangement ?🤔 i don’t want u to get bored so i will skip all the boring definitions and explain with examples .

The Problem

Let’s say there are 5 persons and they are standing initially on same coloured blocks as shown in the pic

now if i ask u what are the total no of ways of arranging them on these 5 blocks then your answer will be P(5,5) i.e. the total number of permutations .Now there are total P(5,5) ways of arranging them but what if i ask you to tell me the number of arrangements of persons on blocks such that no person is on its own block .It means that in all those arrangements person red can not take block red and person green can not take block green and so on……. This is exactly what derangements are 👴

“A Derangement is a permutation of n elements, such that no element appears in its original position.”

Intuitive Solution

now that you have known about derangements let’s discuss the solution to this problem .Well most intuitive approach that comes to our mind is find all those permutations and see each of them one by one whether any of them contains a person on same colour block and if it is so we will not take that case in our answer because we want those cases in which no person is on its own block. This way we will count all those permutations that fulfil our conditions .

So what is wrong with this approach?😐Actually its about time complexity ,this approach is too much time consuming . if you go on finding each of the permutations and then exploring each of them to find cases in them it takes a worst case time complexity of O(n*n!) .🤐Now i guess you yourself have understood why this approach is bad. So what is A better approach 🤔.

Better Approach

Well the better approach is to reduce this problem into subproblems .Let’s introduce a function first

D(n)=derangements of n persons

Now lets say we have these n=5 persons as follows initially .

every person is on its own colour block initially .So let’s start from red ,and give person red a block different from red . We have 4 choices here.

lets choose blue coloured block . person red takes blue coloured block.

So now person red is not on its original position. Now person red is okay(not on original block) and we are left with this situation.

So D(5)= 4*(no. of derangements of subproblem we get) or D(n)=(n-1)*(no. of derangements of subproblem we get)

So person blue has two choices here whether to take red coloured block or not .

CASE -1 (person blue takes the red block ) CASE -2 (person blue takes a block other than red )

so in our function we can write this as following

D(5)=4*(no of derangements of remaining persons in case 1 + no of derangements of remaining persons in case 2)

or if we generalize this

D(n)=(n-1)*(no of derangements of remaining persons in case 1 + no of derangements of remaining persons in case 2)

CASE -1 (person blue takes the red block )

So, we have reduced our problem from 5 to 3 persons 😃because person blue and person red are on a different colour block and we are left with only 3 persons who are on their original block .

So we have

no of derangements of remaining persons in case 1 = D(3)

or if we generalize

no of derangements of remaining persons in case 1 = D(n-2)

CASE -2 (person blue takes a block other than red )

So , we have to arrange 4 persons who do not want to be on their own blocks right. Person Blue can not take red coloured block and the rest three also can not take their own blocks because of same colour so the problem reduces to 4 persons to be arranged on different blocks than theirs .

no of derangements of remaining persons in case 2= D(4)

or if we generalize

no of derangements of remaining persons in case 2= D(n-1)

So by summing this up ,we can write as

Let D(n) be count of derangements for n elements. Below is the recursive relation to it.

D(n) = (n - 1) * [D(n - 1) + D(n - 2)]

here is a C++ implementation of the program to find no of derangements using this recurrence relation .



#include <bits/stdc++.h>

using namespace std; int D(int n)

{

// Base cases

if (n == 1) return 0;

if (n == 2) return 1;

return (n — 1) * (D(n — 1) + D(n — 2));

} // Driver Code

int main()

{

int n = 4;

cout << “Count of Derangements is “

<< D(n);

return 0;

}

Well there is still a problem 😅 left. We are not fully done yet this code is still giving exponential time complexity .

Time Complexity: T(n) = T(n-1) + T(n-2) which is exponential.

let’s look at the recursion tree of this solution

Did you observe something ?🧐👴

Observe that there is repetition of work . See recursion tree for D(5), D(3) is being evaluated twice.

Efficient Solution

Use Dynamic Programming to store results of subproblems in an array and build the array in bottom-up manner.

// A Dynamic programming based C++ // program to count derangements #include <bits/stdc++.h> using namespace std; int countD(int n) { // Create an array to store // counts for subproblems int D[n + 1] = {0}; // Base cases D[1] = 0; D[2] = 1; // Fill der[0..n] in bottom up manner // using above recursive formula for (int i = 3; i <= n; ++i) D[i] = (i - 1) * (D[i - 1] + D[i - 2]); // Return result for n return D[n]; } // Driver code int main() { int n = 4; cout << "Count of Derangements is " << countD(n); return 0; }

Time Complexity : O(n)

Auxiliary Space : O(n)

There is still improvement possible in this solution .

We can actually reduce the extra space we have used in the above approach. As we only need to remember only two previous values So, instead of Storing the values in an array two variables can be used to just store the required previous only. Try that on your own .

I hope you get the trick 😃.