Open In App

Number of permutation with K inversions

Last Updated : 08 Mar, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

We are given two numbers n and k, the task is to find how many permutations of the first n number have exactly k inversion. Two elements in a sequence form an inversion if the smaller element appears before the larger element.

Examples: 

Input: n = 3, k = 1
Output: 2
Explanation: Total Permutation of first 3 numbers are 123, 132, 213, 231, 312, 321
Permutation with 1 inversion: 132 and 213

Input: n = 3, k = 3
Output: 1
Explanation: Permutation with 3 inversions: 321

Using Recursion - O(n! * k) Time and O(n) Space

Base Cases:

  • If n == 0, no permutations are possible, so return 0.
  • If k == 0, there is exactly one permutation (the sorted order), so return 1.

Recursive Relation:

  • For each possible position i where the nth element can be placed (where i ranges from 0 to min(k, n-1)), we recursively call the function to calculate the number of permutations of n-1 elements with k-i inversions. This represents placing the nth element in a way that creates i inversions.

countPermWithkInversions(n, k) = Σ(countPermWithkInversions(n-1, k-i)) for i = 0 to min(k, n-1)

C++
// C++ code to count permutations with exactly
// k inversions using Recursion
#include <iostream>
using namespace std;

int countPermWithkInversions(int n, int k) {
  
    // Base cases
    // no permutations possible with 0 elements
    if (n == 0) return 0;  
  
     // Only one way to have 0 inversions: sorted order
    if (k == 0) return 1;     

    // Initialize result for this recursive step
    int result = 0;

    // Recursively sum up all valid counts 
    // by placing the nth largest element
    // in positions that create the 
    // required inversion counts
    for (int i = 0; i <= min(k, n - 1); i++) {
        result += countPermWithkInversions(n - 1, k - i);
    }

    return result;
}

int main() {
  
    int n = 4; 
    int k = 2; 

    cout << countPermWithkInversions(n, k);

    return 0;
}
Java
// Java code to count permutations with 
// exactly k inversions using Recursion
class GfG {

    static int countPermWithkInversions(int n, int k) {

        // Base cases
        // no permutations possible with 0 elements
        if (n == 0) return 0;

        // Only one way to have 0 inversions: sorted order
        if (k == 0) return 1;

        // Initialize result for this recursive step
        int result = 0;

        // Recursively sum up all valid counts
        // by placing the nth largest element
        // in positions that create the
        // required inversion counts
        for (int i = 0; i <= Math.min(k, n - 1); i++) {
            result += countPermWithkInversions(n - 1, k - i);
        }

        return result;
    }

    public static void main(String[] args) {

        int n = 4;
        int k = 2;

        System.out.println(countPermWithkInversions(n, k));
    }
}
Python
# Python code to count permutations with exactly
# k inversions using Recursion
def countPermWithkInversions(n, k):

    # Base cases
    # no permutations possible with 0 elements
    if n == 0:
        return 0

    # Only one way to have 0 inversions: sorted order
    if k == 0:
        return 1

    # Initialize result for this recursive step
    result = 0

    # Recursively sum up all valid counts
    # by placing the nth largest element
    # in positions that create the
    # required inversion counts
    for i in range(min(k, n - 1) + 1):
        result += countPermWithkInversions(n - 1, k - i)

    return result
  
if __name__ == "__main__":
  
    n = 4
    k = 2

    print(countPermWithkInversions(n, k))
C#
// C# code  to count permutations with exactly 
// k inversions using Recursion
using System;

class GfG {

    static int countPermWithkInversions(int n, int k) {

        // Base cases
        // no permutations possible with 0 elements
        if (n == 0) return 0;

        // Only one way to have 0 inversions: sorted order
        if (k == 0) return 1;

        // Initialize result for this recursive step
        int result = 0;

        // Recursively sum up all valid counts
        // by placing the nth largest element
        // in positions that create the
        // required inversion counts
        for (int i = 0; i <= Math.Min(k, n - 1); i++) {
            result += countPermWithkInversions(n - 1, k - i);
        }

        return result;
    }

    static void Main() {
        int n = 4;
        int k = 2;

        Console.WriteLine(countPermWithkInversions(n, k));
    }
}
JavaScript
// Javascript code to  count permutations with 
// exactly k inversions using Recursion
function countPermWithkInversions(n, k) {

    // Base cases
    // no permutations possible with 0 elements
    if (n === 0) return 0;

    // Only one way to have 0 inversions: sorted order
    if (k === 0) return 1;

    // Initialize result for this recursive step
    let result = 0;

    // Recursively sum up all valid counts
    // by placing the nth largest element
    // in positions that create the
    // required inversion counts
    for (let i = 0; i <= Math.min(k, n - 1); i++) {
        result += countPermWithkInversions(n - 1, k - i);
    }

    return result;
}

const n = 4;
const k = 2;

console.log(countPermWithkInversions(n, k));

Output
5

Using Top-Down DP (Memoization) – O(n*k*k) Time and O(n*k) Space

The above recursive solution satisfies two key properties of Dynamic Programming, enabling us to use memoization for an optimized approach.

1. Optimal Substructure

We solve the problem of counting permutations with exactly k inversions by breaking it into subproblems involving fewer elements and inversions. Specifically, if we have n elements and k required inversions, we can compute it by trying positions for the largest element in a way that contributes to the inversion count.

The recursive relation is:

  • countPermWithkInversions(n, k) = Σ countPermWithkInversions(n-1, k-i)

Here, we consider placing the largest element in positions that create i inversions, where i ranges from 0 to min(k, n-1).

2. Overlapping Subproblems:

Many subproblems are computed multiple times when finding permutations for smaller subsets and inversion counts. For example, while calculating the result for (n, k), subproblems for (n-1, k-i) are encountered repeatedly.

We use a 2D array memo of size (n+1) x (k+1), initialized to -1, to store results of subproblems. If a result is already stored in memo[n][k], we return it directly, avoiding redundant calculations.

C++
// C++ code to find number of permutation 
// with k inversion using Memoization
#include <bits/stdc++.h>
using namespace std;

// Helper function for recursive computation
int kInversionsHelper(int n, int k,
                      vector<vector<int>>& memo) {
  
    // Base case: If there are no elements,
    // no permutations are possible
    if (n == 0) return 0;

    // Base case: If k is 0, only one way to 
    // have 0 inversions: sorted order
    if (k == 0) return 1;

    // Check if the result is already 
    // computed (memoization)
    if (memo[n][k] != -1) return memo[n][k];

    int result = 0;

    // Loop through possible inversion counts 
    // for the nth largest element
    for (int i = 0; i <= min(k, n - 1); i++) {
      
        // Recursively count permutations for the 
        // remaining elements and inversions
        result = (result + 
             kInversionsHelper(n - 1, k - i, memo));
    }

    return memo[n][k] = result;
}

// Function to count permutations with k inversions
int countPermWithkInversions(int n, int k) {
  
    // Initialize memoization table with -1 
    // to indicate uncomputed values
    vector<vector<int>> memo(n + 1, vector<int>(k + 1, -1));
  
    return kInversionsHelper(n, k, memo);
}

int main() {
  
    int n = 4;
    int k = 2; 

    cout << countPermWithkInversions(n, k);

    return 0;
}
Java
// Java code to find number of permutation 
// with k inversions using Memoization
import java.util.Arrays;

class GfG {

    // Helper function for recursive computation
    static int kInversionsHelper(int n, int k, int[][] memo) {
        
        // Base case: If there are no elements,
        // no permutations are possible
        if (n == 0) return 0;

        // Base case: If k is 0, only one way to 
        // have 0 inversions: sorted order
        if (k == 0) return 1;

        // Check if the result is already 
        // computed (memoization)
        if (memo[n][k] != -1) return memo[n][k];

        int result = 0;

        // Loop through possible inversion counts 
        // for the nth largest element
        for (int i = 0; i <= Math.min(k, n - 1); i++) {
          
            // Recursively count permutations for the 
            // remaining elements and inversions
            result = (result 
                + kInversionsHelper(n - 1, k - i, memo));
        }

        return memo[n][k] = result;
    }

    // Function to count permutations with k inversions
    static int countPermWithkInversions(int n, int k) {
        
        // Initialize memoization table with -1 
        // to indicate uncomputed values
        int[][] memo = new int[n + 1][k + 1];
        for (int[] row : memo) {
            Arrays.fill(row, -1);
        }
        
        return kInversionsHelper(n, k, memo);
    }

    public static void main(String[] args) {
        
        int n = 4;
        int k = 2; 

        System.out.println(countPermWithkInversions(n, k));
    }
}
Python
# Python code to find number of permutation 
# with k inversions using Memoization

def kInversionsHelper(n, k, memo):
  
    # Base case: If there are no elements,
    # no permutations are possible
    if n == 0:
        return 0

    # Base case: If k is 0, only one way to 
    # have 0 inversions: sorted order
    if k == 0:
        return 1

    # Check if the result is already 
    # computed (memoization)
    if memo[n][k] != -1:
        return memo[n][k]

    result = 0

    # Loop through possible inversion counts 
    # for the nth largest element
    for i in range(min(k, n - 1) + 1):
      
        # Recursively count permutations for the 
        # remaining elements and inversions
        result = (result + kInversionsHelper(n - 1, k - i, memo))

    memo[n][k] = result
    return result

def countPermWithkInversions(n, k):
  
    # Initialize memoization table with -1 
    # to indicate uncomputed values
    memo = [[-1 for _ in range(k + 1)] for _ in range(n + 1)]
    return kInversionsHelper(n, k, memo)

if __name__ == "__main__":
  
    n = 4
    k = 2 

    print(countPermWithkInversions(n, k))
C#
// C# code to find number of permutation 
// with k inversions using Memoization
using System;

class GfG {
    
    // Helper function for recursive computation
   	static int kInversionsHelper(int n, int k, int[,] memo) {
        
        // Base case: If there are no elements,
        // no permutations are possible
        if (n == 0) return 0;

        // Base case: If k is 0, only one way to 
        // have 0 inversions: sorted order
        if (k == 0) return 1;

        // Check if the result is already 
        // computed (memoization)
        if (memo[n, k] != -1) return memo[n, k];

        int result = 0;

        // Loop through possible inversion counts 
        // for the nth largest element
        for (int i = 0; i <= Math.Min(k, n - 1); i++) {
          
            // Recursively count permutations for the 
            // remaining elements and inversions
            result = (result + kInversionsHelper(n - 1, k - i, memo));
        }

        return memo[n, k] = result;
    }

    static int countPermWithkInversions(int n, int k) {
        
        // Initialize memoization table with -1 
        // to indicate uncomputed values
        int[,] memo = new int[n + 1, k + 1];
        for (int i = 0; i < memo.GetLength(0); i++) {
            for (int j = 0; j < memo.GetLength(1); j++) {
                memo[i, j] = -1;
            }
        }

        return kInversionsHelper(n, k, memo);
    }

    static void Main() {
        
        int n = 4;
        int k = 2; 

        Console.WriteLine(countPermWithkInversions(n, k));
    }
}
JavaScript
// JavaScript code to find number of permutation
// with k inversions using Memoization

function kInversionsHelper(n, k, memo) {

    // Base case: If there are no elements,
    // no permutations are possible
    if (n === 0)
        return 0;

    // Base case: If k is 0, only one way to
    // have 0 inversions: sorted order
    if (k === 0)
        return 1;

    // Check if the result is already
    // computed (memoization)
    if (memo[n][k] !== -1)
        return memo[n][k];

    let result = 0;

    // Loop through possible inversion counts
    // for the nth largest element
    for (let i = 0; i <= Math.min(k, n - 1); i++) {

        // Recursively count permutations for the
        // remaining elements and inversions
        result = (result
                  + kInversionsHelper(n - 1, k - i, memo));
    }

    memo[n][k] = result;
    return result;
}

function countPermWithkInversions(n, k) {

    // Initialize memoization table with -1
    // to indicate uncomputed values
    const memo = Array.from({length : n + 1},
                            () => Array(k + 1).fill(-1));
    return kInversionsHelper(n, k, memo);
}

const n = 4;
const k = 2;

console.log(countPermWithkInversions(n, k));

Output
5

Using Bottom-Up DP (Tabulation) – O(n*k*k) Time and O(n*k) Space

We create a 2D array dp of size (n + 1)*(k + 1), where the state dp[l][r] represents the number of permutations of l elements with exactly r inversions.

Base Case: dp[l][0] = 1 for all l, since there's only one way to have zero inversions-by arranging elements in sorted order.

For each element count l from 1 to n:

  • For each inversion count r from 1 to k, calculate the number of valid permutations.
  • To compute dp[l][r], we iterate over all possible positions of the largest element, which can create up to min(r, l-1) inversions, summing up the results from previous states

This relation fills the DP table by counting valid permutations based on subproblems:

  • dp[l][r] = sum of dp[l-1][r-i] for all valid i.

The final result is stored in dp[n][k], representing the total permutations of n elements with exactly k inversions.

C++
// C++ code to find number of permutation 
// with K inversions using Tabulation
#include <bits/stdc++.h>
using namespace std;

int countPermWithkInversions(int n, int k) {
  
    // Initialize a 2D table for dynamic programming
    vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));

    // Base case: If k is 0, only one way to 
    // have 0 inversions: sorted order
    for (int l = 0; l <= n; l++) {
        dp[l][0] = 1;
    }

    // Fill the table using the tabulation method
    for (int l = 1; l <= n; l++) {
        for (int r = 1; r <= k; r++) {
            for (int i = 0; i <= min(r, l - 1); i++) {
              
                // Count permutations for the remaining 
                // elements and inversions
                dp[l][r] = (dp[l][r] + dp[l - 1][r - i]);
            }
        }
    }

    return dp[n][k];
}

int main() {

    int n = 4;
    int k = 2; 

    cout << countPermWithkInversions(n, k);

    return 0;
}
Java
// Java code to find number of permutation 
// with K inversions using Tabulation
import java.util.Arrays;

class GfG {
    static int countPermWithkInversions(int n, int k) {
      
        // Initialize a 2D table for dynamic programming
        int[][] dp = new int[n + 1][k + 1];

        // Base case: If k is 0, only one way to 
        // have 0 inversions: sorted order
        for (int l = 0; l <= n; l++) {
            dp[l][0] = 1;
        }

        // Fill the table using the tabulation method
        for (int l = 1; l <= n; l++) {
            for (int r = 1; r <= k; r++) {
                for (int i = 0; i <= Math.min(r, l - 1); i++) {
                  
                    // Count permutations for the remaining 
                    // elements and inversions
                    dp[l][r] = (dp[l][r] + dp[l - 1][r - i]);
                }
            }
        }

        return dp[n][k];
    }

    public static void main(String[] args) {
      
        int n = 4;
        int k = 2; 

        System.out.println(countPermWithkInversions(n, k));
    }
}
Python
# Python code to find number of permutation 
# with k inversions using Tabulation

def countPermWithkInversions(n, k):
  
    # Initialize a 2D table for dynamic programming
    dp = [[0] * (k + 1) for _ in range(n + 1)]

    # Base case: If k is 0, only one way to 
    # have 0 inversions: sorted order
    for l in range(n + 1):
        dp[l][0] = 1

    # Fill the table using the tabulation method
    for l in range(1, n + 1):
        for r in range(1, k + 1):
            for i in range(min(r, l - 1) + 1):
              
                # Count permutations for the remaining 
                # elements and inversions
                dp[l][r] = (dp[l][r] + dp[l - 1][r - i])

    return dp[n][k]
  
if __name__ == "__main__":

    n = 4
    k = 2 

    print(countPermWithkInversions(n, k))
C#
// C# code to find number of permutation 
// with k inversions using Tabulation
using System;

class GfG {
    static int countPermWithkInversions(int n, int k) {
      
        // Initialize a 2D table for dynamic programming
        int[,] dp = new int[n + 1, k + 1];

        // Base case: If k is 0, only one way to 
        // have 0 inversions: sorted order
        for (int l = 0; l <= n; l++) {
            dp[l, 0] = 1;
        }

        // Fill the table using the tabulation method
        for (int l = 1; l <= n; l++) {
            for (int r = 1; r <= k; r++) {
                for (int i = 0; i <= Math.Min(r, l - 1); i++) {
                  
                    // Count permutations for the remaining 
                    // elements and inversions
                    dp[l, r] = (dp[l, r] + dp[l - 1, r - i]);
                }
            }
        }

        return dp[n, k];
    }

    static void Main() {
      
        int n = 4;
        int k = 2; 

        Console.WriteLine(countPermWithkInversions(n, k));
    }
}
JavaScript
// JavaScript code to find number of permutation 
// with k inversions using Tabulation

function countPermWithkInversions(n, k) {

    // Initialize a 2D table for dynamic programming
    const dp = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0));

    // Base case: If k is 0, only one way to 
    // have 0 inversions: sorted order
    for (let l = 0; l <= n; l++) {
        dp[l][0] = 1;
    }

    // Fill the table using the tabulation method
    for (let l = 1; l <= n; l++) {
        for (let r = 1; r <= k; r++) {
            for (let i = 0; i <= Math.min(r, l - 1); i++) {
            
                // Count permutations for the remaining 
                // elements and inversions
                dp[l][r] = (dp[l][r] + dp[l - 1][r - i]);
            }
        }
    }

    return dp[n][k];
}

let n = 4;
let k = 2;

console.log(countPermWithkInversions(n, k));

Output
5

Time Complexity: O(n*k*k), where n is the number of elements and k is the number of inversions, due to the nested loops iterating through n, k, and possible inversions.
Auxiliary Space: O(n*k), because we maintain a 2D table of size (n+1)×(k+1) to store the computed values for dynamic programming.


Next Article

Similar Reads