Skip to content
Related Articles

Related Articles

Improve Article

Number of permutation with K inversions

  • Difficulty Level : Hard
  • Last Updated : 08 Jul, 2021

Given an array, an inversion is defined as a pair a[i], a[j] such that a[i] > a[j] and i < j. We are given two numbers N and k, we need to tell how many permutation of first N number have exactly K inversion.

Examples: 

Input  : N = 3, K = 1
Output : 2
Explanation :  
Total Permutation of first N number,
123, 132, 213, 231, 312, 321
Permutation with 1 inversion : 132 and 213

Input  : N = 4, K = 2
Output : 5

A Naïve way to solve this problem is noting down all permutation then checking count of inversion in them but iterating through permutation itself will take O(N!) time, which is too large. 

We can solve this problem using dynamic programming approach. Below is recursive formula.  

If N is 0, Count(0, K) = 0

If K is 0, Count(N, 0) = 1 (Only sorted array)

In general case, 
If we have N number and require K inversion, 
Count(N, K) = Count(N - 1, K) + 
              Count(N – 1, K - 1) + 
              Count(N – 1, K – 2) + 
              .... + 
              Count(N – 1, 0)

How does above recursive formula work? 
If we have N number and want to have K permutation and suppose all permutation of (N – 1) number are written somewhere, the new number (Nth number and largest) need to be placed in all permutation of (N – 1) number and those whose inversion count becomes K after adding this number should be added in our answer. Now take those set of permutation of (N – 1) number which has let (K – 3) inversion, now we can place this new largest number at position 3 from last, then inversion count will be K, so count(N – 1, K – 3) should be added to our answer, same argument can be given for other inversion also and we will reach to above recursion as final answer.



Below code is written following above recursion in memorization way.  

C++




// C++ program to find number of permutation
// with K inversion using Memoization
#include <bits/stdc++.h>
using namespace std;
 
// Limit on N and K
const int M = 100;
 
// 2D array memo for stopping
// solving same problem again
int memo[M][M];
 
// method recursively calculates
// permutation with K inversion
int numberOfPermWithKInversion(int N, int K)
{
     
    // base cases
    if (N == 0)
        return 0;
    if (K == 0)
        return 1;
 
    // if already solved then
    // return result directly
    if (memo[N][K] != 0)
        return memo[N][K];
 
    // calling recursively all subproblem
    // of permutation size N - 1
    int sum = 0;
    for (int i = 0; i <= K; i++)
    {
 
        // Call recursively only
        // if total inversion
        // to be made are less
        // than size
        if (i <= N - 1)
            sum += numberOfPermWithKInversion(N - 1,
                                              K - i);
    }
 
    // store result into memo
    memo[N][K] = sum;
 
    return sum;
}
 
// Driver code
int main()
{
    int N = 4;
    int K = 2;
    cout << numberOfPermWithKInversion(N, K);
    return 0;
}

Java




// Java program to find number of permutation with
// K inversion using Memoization
 
import java.io.*;
 
class GFG {
     
    // Limit on N and K
    static int M = 100;
 
    // 2D array memo for stopping solving same problem
    // again
    static int memo[][] = new int[M][M];
 
    // method recursively calculates permutation with
    // K inversion
    static int numberOfPermWithKInversion(int N, int K)
    {
         
        // base cases
        if (N == 0)
            return 0;
        if (K == 0)
            return 1;
 
        // if already solved then return result directly
        if (memo[N][K] != 0)
            return memo[N][K];
 
        // calling recursively all subproblem of
        // permutation size N - 1
        int sum = 0;
        for (int i = 0; i <= K; i++) {
             
            // Call recursively only if total inversion
            // to be made are less than size
            if (i <= N - 1)
                sum += numberOfPermWithKInversion(N - 1,
                                                  K - i);
        }
 
        // store result into memo
        memo[N][K] = sum;
 
        return sum;
    }
 
    // Driver code to test above methods
    public static void main(String[] args)
    {
        int N = 4;
        int K = 2;
        System.out.println(numberOfPermWithKInversion(N, K));
    }
}
 
// This code is contributed by vt_m.

Python3




# Python3 program to find number of permutation
# with K inversion using Memoization
 
# Limit on N and K
M = 100
 
# 2D array memo for stopping 
# solving same problem again
memo = [[0 for i in range(M)] for j in range(M)]
  
# method recursively calculates
# permutation with K inversion
def numberOfPermWithKInversion(N, K):
 
    # Base cases
    if (N == 0): return 0
    if (K == 0): return 1
 
    # If already solved then
    # return result directly
    if (memo[N][K] != 0):
        return memo[N][K]
 
    # Calling recursively all subproblem
    # of permutation size N - 1
    sum = 0
    for i in range(K + 1):
     
        # Call recursively only if
        # total inversion to be made
        # are less than size
        if (i <= N - 1):
            sum += numberOfPermWithKInversion(N - 1, K - i)
     
    # store result into memo
    memo[N][K] = sum
 
    return sum
 
# Driver code
N = 4; K = 2
print(numberOfPermWithKInversion(N, K))
 
# This code is contributed by Anant Agarwal.

C#




// C# program to find number of
// permutation with K inversion
// using Memoization
using System;
 
class GFG
{
 
// Limit on N and K
static int M = 100;
 
// 2D array memo for stopping
// solving same problem again
static int [,]memo = new int[M, M];
 
// method recursively calculates
// permutation with K inversion
static int numberOfPermWithKInversion(int N,
                                      int K)
{
     
    // base cases
    if (N == 0)
        return 0;
    if (K == 0)
        return 1;
 
    // if already solved then
    // return result directly
    if (memo[N, K] != 0)
        return memo[N, K];
 
    // calling recursively all
    // subproblem of permutation
    // size N - 1
    int sum = 0;
    for (int i = 0; i <= K; i++)
    {
         
        // Call recursively only if
        // total inversion to be
        // made are less than size
        if (i <= N - 1)
            sum += numberOfPermWithKInversion(N - 1,
                                              K - i);
    }
 
    // store result into memo
    memo[N, K] = sum;
 
    return sum;
}
 
// Driver Code
static public void Main ()
{
    int N = 4;
    int K = 2;
    Console.WriteLine(numberOfPermWithKInversion(N, K));
}
}
 
// This code is contributed by ajit

PHP




<?php
// PHP program to find number of permutation
// with K inversion using Memoization
 
// method recursively calculates
// permutation with K inversion
function numberOfPermWithKInversion($N, $K)
{
     
    $memo = array();
     
    // base cases
    if ($N == 0)
        return 0;
    if ($K == 0)
        return 1;
 
    // if already solved then
    // return result directly
    if ($memo[$N][$K] != 0)
        return $memo[$N][$K];
 
    // calling recursively all subproblem
    // of permutation size N - 1
    $sum = 0;
    for ($i = 0; $i <= $K; $i++)
    {
 
        // Call recursively only
        // if total inversion
        // to be made are less
        // than size
        if ($i <= $N - 1)
            $sum += numberOfPermWithKInversion($N - 1,
                                               $K - $i);
    }
 
    // store result into memo
    $memo[$N][$K] = $sum;
 
    return $sum;
}
 
// Driver code
$N = 4;
$K = 2;
echo numberOfPermWithKInversion($N, $K);
 
// This code is contributed
// by Akanksha Rai(Abby_akku)
?>

Javascript




<script>
 
// Javascript program to find number of
// permutation with K inversion using
// Memoization
 
// Limit on N and K
let M = 100;
 
// 2D array memo for stopping solving
// same problem again
let memo = new Array(M);
for(let i = 0; i < M; i++)
{
    memo[i] = new Array(M);
    for(let j = 0; j < M; j++)
    {
        memo[i][j] = 0;
    }
}
 
// Method recursively calculates permutation
// with K inversion
function numberOfPermWithKInversion(N, K)
{
     
    // base cases
    if (N == 0)
        return 0;
    if (K == 0)
        return 1;
 
    // If already solved then return
    // result directly
    if (memo[N][K] != 0)
        return memo[N][K];
 
    // Calling recursively all subproblem of
    // permutation size N - 1
    let sum = 0;
    for(let i = 0; i <= K; i++)
    {
         
        // Call recursively only if total inversion
        // to be made are less than size
        if (i <= N - 1)
            sum += numberOfPermWithKInversion(
                N - 1, K - i);
    }
     
    // Store result into memo
    memo[N][K] = sum;
 
    return sum;
}
 
// Driver code
let N = 4;
let K = 2;
 
document.write(numberOfPermWithKInversion(N, K));
 
// This code is contributed by divyesh072019 
 
</script>
Output
5

Time Complexity: O(N*N*K)

Optimized Approach: Using Tabulation and cumulative sum

C++




// C++ program to find number of permutation
// with K inversions
 
#include <bits/stdc++.h>
using namespace std;
 
int numberOfPermWithKInversions(int N, int K) {
    vector<vector<int>> dp(N+1,vector<int>(K+1));
   
    // As for k=0, number of permutations is 1 for every N
      for(int i = 1; i <= N; i++)
        dp[i][0] = 1;
 
      // Using Dynamic Programming with cumulative sum
    for(int i = 1; i <= N; i++)
    {
        for(int j = 1; j <= K; j++)
        {
              // This is same as val = dp[i-1][j] - dp[i-1][j-i]
              // i.e. dp[i-1][j........j-i], just taking care of
              // boundaries
            int val = dp[i-1][j];
            if(j >= i)
                val -= dp[i-1][j-i];
 
            dp[i][j] = dp[i][j-1] + val;
        }
    }
   
      // And, in the end calculate the dp[n][k]
      // which is dp[n][k]-dp[n][k-1]
    int ans = dp[N][K];
    if(K >= 1)
        ans -= dp[N][K-1];
 
    return ans;
}
 
int main() {
    int N = 4;
    int K = 2;
     
      cout << numberOfPermWithKInversions(N,K) << "\n";
    return 0;
}
Output
5

Time Complexity: O(N*K)

This article is contributed by Utkarsh Trivedi and Ankit Kumar Sharma. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :