{x}
blog image

Find the Derangement of An Array

Solution Explanation for Find the Derangement of An Array

This problem asks to find the number of derangements of an array of integers from 1 to n, where a derangement is a permutation such that no element is in its original position. We'll explore two solutions: dynamic programming with and without space optimization.

Approach 1: Dynamic Programming

This approach uses dynamic programming to efficiently calculate the number of derangements.

State Definition:

Let dp[i] represent the number of derangements of an array of size i.

Base Cases:

  • dp[0] = 1 (There's one way to derange an empty array)
  • dp[1] = 0 (There's no way to derange an array of size 1)

Recurrence Relation:

For an array of size i, consider the placement of the element 1. We have i-1 choices for its position.

  • Case 1: If we place 1 in position j, and then place j in position 1, we are left with i-2 elements to derange. This contributes (i-1) * dp[i-2] derangements.
  • Case 2: If we place 1 in position j, but don't place j in position 1, we have i-1 elements left to derange. This contributes (i-1) * dp[i-1] derangements.

Therefore, the recurrence relation is:

dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2])

Algorithm:

  1. Initialize dp[0] and dp[1] with base cases.
  2. Iterate from i = 2 to n, calculating dp[i] using the recurrence relation.
  3. Return dp[n]. Remember to take the modulo with 10^9 + 7 to handle large results.

Time and Space Complexity:

  • Time Complexity: O(n) - We iterate through the dp array once.
  • Space Complexity: O(n) - We store the dp array.

Approach 2: Dynamic Programming with Space Optimization

We observe that the recurrence relation only depends on the previous two values (dp[i-1] and dp[i-2]). Therefore, we can optimize space by only storing these two values instead of the entire array.

Algorithm:

  1. Initialize a = 1 and b = 0 (representing dp[0] and dp[1] respectively).
  2. Iterate from i = 2 to n.
  3. In each iteration, calculate the next value c = (i - 1) * (a + b) % mod.
  4. Update a = b and b = c.
  5. After the loop, b will hold the final result dp[n].

Time and Space Complexity:

  • Time Complexity: O(n) - Same as before.
  • Space Complexity: O(1) - We only store a constant number of variables.

Code Implementation (Python)

Approach 1:

class Solution:
    def findDerangement(self, n: int) -> int:
        mod = 10**9 + 7
        dp = [1, 0] + [0] * (n - 1)  # Initialize dp array
        for i in range(2, n + 1):
            dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2]) % mod
        return dp[n]
 

Approach 2:

class Solution:
    def findDerangement(self, n: int) -> int:
        mod = 10**9 + 7
        a, b = 1, 0
        for i in range(2, n + 1):
            a, b = b, ((i - 1) * (a + b)) % mod
        return b

The code in other languages (Java, C++, Go) follows similar logic, adapting the syntax and data types accordingly as shown in the original response. The space-optimized version is generally preferred due to its lower memory usage, especially for large values of n.