Skip to main content

Count the Number of Inversions - Solution & Explanation

HardArrayDynamic Programming10 min readAsked at: Amazon, Microsoft, Salesforce +2
Practice this problem

Problem Statement

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]
    • Prefix [2, 0, 1] has inversions (0, 1) and (0, 2).
    • Prefix [2] has 0 inversions.
  • [1, 2, 0]
    • Prefix [1, 2, 0] has inversions (0, 2) and (1, 2).
    • Prefix [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]:

  • Prefix [2, 0, 1] has inversions (0, 1) and (0, 2).
  • Prefix [2, 0] has an inversion (0, 1).
  • Prefix [2] has 0 inversions.

Example 3:

Input: n = 2, requirements = [[0,0],[1,0]]

Output: 1

Explanation:

The only satisfying permutation is [0, 1]:

  • Prefix [0] has 0 inversions.
  • Prefix [0, 1] has an inversion (0, 1).

 

Constraints:

  • 2 <= n <= 300
  • 1 <= requirements.length <= n
  • requirements[i] = [endi, cnti]
  • 0 <= endi <= n - 1
  • 0 <= cnti <= 400
  • The input is generated such that there is at least one i such that endi == n - 1.
  • The input is generated such that all endi are unique.

Approach Overview

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.

Solution

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$.

Code

Python

Java

C++

Go

TypeScript

Try this approach in the editor →

Detailed Complexity Analysis

ApproachTimeSpaceWhen to Use
Brute Force PermutationsO(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 OptimizationO(n * k)O(n * k)Optimal solution for large constraints and typical interview expectations

Video Solution

3193. Count the Number of Inversions | DP Time Complexity | Two Pointer | DP Space Optimized • Aryan Mittal • 6,967 views views

Watch 4 more video solutions →

Frequently Asked Questions

Is Count the Number of Inversions easy or hard?
Count the Number of Inversions is classified as a Hard problem because it combines permutation combinatorics with dynamic programming optimization. Understanding how inserting elements changes inversion counts is the key insight required to design the correct DP recurrence.
Count the Number of Inversions Python/Java solution
Most implementations build a DP table where dp[i][j] stores counts of permutations with j inversions. The code iterates through permutation sizes and uses prefix sums to compute transitions efficiently. The same logic works in Python, Java, C++, Go, and TypeScript with only syntax differences.
How to solve Count the Number of Inversions in O(n * k)?
Use DP where dp[i][j] counts permutations of length i with j inversions. When inserting element i, it can create between 0 and i-1 new inversions. Using a prefix sum array allows you to compute dp[i][j] as a range sum of dp[i-1] values, reducing the transition to constant time per state.
What is the best approach for Count the Number of Inversions?
The best approach uses dynamic programming where dp[i][j] represents the number of permutations of size i with exactly j inversions. Each new element can be inserted into different positions, creating varying inversion counts. Using prefix sums optimizes the transition and reduces the complexity to O(n * k) time with O(n * k) space.
Is Count the Number of Inversions asked at Google/Amazon/Meta?
Inversion counting and permutation DP problems frequently appear in interviews at companies like Google, Amazon, and Meta. Variants include counting inversions with merge sort, designing DP for permutation statistics, or handling prefix constraints similar to this problem.
What data structure is used in Count the Number of Inversions?
The main structure is a 2D dynamic programming table that tracks permutation length and inversion count. Prefix sum arrays are used to optimize transitions between DP states. The problem primarily relies on dynamic programming rather than complex data structures.
What is the time complexity of Count the Number of Inversions?
The optimized dynamic programming solution runs in O(n * k) time, where n is the permutation size and k is the maximum inversion count considered. Space complexity is also O(n * k) for the DP table. A naive DP approach without prefix optimization would take O(n * k * n) time.

Ready to solve this problem?

Practice Count the Number of Inversions with our built-in code editor and test cases.

Practice on FleetCode