You are given an integer n and a 2D array requirements, where requirements[i] = [endi, cnti] represents the end index and the inversion count of each requirement.
A pair of indices (i, j) from an integer array nums is called an inversion if:
i < j and nums[i] > nums[j]Return the number of permutations perm of [0, 1, 2, ..., n - 1] such that for all requirements[i], perm[0..endi] has exactly cnti inversions.
Since the answer may be very large, return it modulo 109 + 7.
Example 1:
Input: n = 3, requirements = [[2,2],[0,0]]
Output: 2
Explanation:
The two permutations are:
[2, 0, 1]
[2, 0, 1] has inversions (0, 1) and (0, 2).[2] has 0 inversions.[1, 2, 0]
[1, 2, 0] has inversions (0, 2) and (1, 2).[1] has 0 inversions.Example 2:
Input: n = 3, requirements = [[2,2],[1,1],[0,0]]
Output: 1
Explanation:
The only satisfying permutation is [2, 0, 1]:
[2, 0, 1] has inversions (0, 1) and (0, 2).[2, 0] has an inversion (0, 1).[2] has 0 inversions.Example 3:
Input: n = 2, requirements = [[0,0],[1,0]]
Output: 1
Explanation:
The only satisfying permutation is [0, 1]:
[0] has 0 inversions.[0, 1] has an inversion (0, 1).
Constraints:
2 <= n <= 3001 <= requirements.length <= nrequirements[i] = [endi, cnti]0 <= endi <= n - 10 <= cnti <= 400i such that endi == n - 1.endi are unique.Problem Overview: You are given constraints about inversion counts in permutations. An inversion is a pair (i, j) where i < j and nums[i] > nums[j]. The task is to count how many valid permutations satisfy the required inversion conditions.
Approach 1: Brute Force Permutation Enumeration (O(n! * n), O(n))
Generate every permutation of the numbers 1..n. For each permutation, iterate through all index pairs and count inversions. After computing the inversion count, verify whether it satisfies the required condition. This approach is straightforward but infeasible beyond very small n because generating permutations costs O(n!) time. It mainly helps build intuition about how inversion counts behave in permutations.
Approach 2: Dynamic Programming on Permutation Size (O(n * k), O(n * k))
The key insight: when inserting the next largest number into a permutation, you control how many new inversions it creates. Define dp[i][j] as the number of permutations of length i that contain exactly j inversions. When placing the element i, it can be inserted in any of the i positions. Inserting it near the front adds more inversions, while inserting near the end adds fewer. The transition becomes dp[i][j] = sum(dp[i-1][j-x]) for all valid x positions where 0 ≤ x < i. This builds permutations incrementally while tracking inversion counts.
To make this efficient, compute transitions using prefix sums so each state can be calculated in constant time instead of iterating through all insertion positions. This reduces the complexity from O(n * k * n) to O(n * k). The DP table effectively enumerates all possible ways to distribute inversions across permutation sizes.
The constraints in the problem restrict which inversion counts are allowed for specific prefixes. While filling the DP table, you simply zero out states that violate those constraints. This filtering ensures that only permutations meeting all requirements remain counted.
This solution combines classic permutation inversion DP with constraint filtering. The reasoning heavily relies on understanding how inversions change when inserting elements into a sequence. Problems involving permutation structure and inversion counts often fall under Dynamic Programming combined with careful reasoning on Array positions and prefix properties.
Recommended for interviews: The dynamic programming approach with prefix-sum optimization is the expected solution. Brute force permutation generation demonstrates understanding of inversion definitions, but the DP formulation shows algorithmic maturity and the ability to optimize combinatorial counting problems.
We define f[i][j] as the number of permutations of [0..i] with j inversions. Consider the relationship between the number a_i at index i and the previous i numbers. If a_i is smaller than k of the previous numbers, then each of these k numbers forms an inversion pair with a_i, contributing to k inversions. Therefore, we can derive the state transition equation:
$
f[i][j] = sum_{k=0}^{min(i, j)} f[i-1][j-k]
Since the problem requires the number of inversions in [0..end_i] to be cnt_i, when we calculate for i = end_i, we only need to compute f[i][cnt_i]. The rest of f[i][..] will be 0.
The time complexity is O(n times m times min(n, m)), and the space complexity is O(n times m). Here, m is the maximum number of inversions, and in this problem, m \le 400$.
Python
Java
C++
Go
TypeScript
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Brute Force Permutations | O(n! * n) | O(n) | Small n or for understanding inversion counting logic |
| Dynamic Programming (Basic Transition) | O(n * k * n) | O(n * k) | When implementing the straightforward DP relation for inversion insertion |
| Dynamic Programming with Prefix Sum Optimization | O(n * k) | O(n * k) | Optimal solution for large constraints and typical interview expectations |
3193. Count the Number of Inversions | DP Time Complexity | Two Pointer | DP Space Optimized • Aryan Mittal • 6,349 views views
Watch 3 more video solutions →Practice Count the Number of Inversions with our built-in code editor and test cases.
Practice on FleetCode