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 permutations of the 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 permutations then checking the 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 a dynamic programming approach. Below is the 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 the 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 sets 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, the same argument can be given for another inversion also and we will reach to above recursion as the final answer.
The below code is written following the above recursion in a memorization way.
// 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 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 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# 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 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) ?> |
<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> |
5
Time Complexity: O(N*N*K)
Space Complexity: O(N*K)
Optimized Approach: Using Tabulation and cumulative sum
// 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;
} |
/*package whatever //do not write package name here */ import java.io.*;
class GFG {
static int numberOfPermWithKInversion( int N, int K)
{
int [][] dp = new int [N + 1 ][K + 1 ];
for ( int i = 1 ; i <= N; i++)
dp[i][ 0 ] = 1 ;
for ( int i = 1 ; i <= N; i++)
{
for ( int j = 1 ; j <= K; j++)
{
// 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;
}
public static void main (String[] args) {
int N = 4 ;
int K = 2 ;
System.out.println(numberOfPermWithKInversion(N, K));
}
} |
# Python program to find number of permutation # with K inversions def numberOfPermWithKInversions(N, K):
List1, List2 = (K + 1 , N + 1 )
dp = [[ 0 for I in range (List1)] for j in range (List2)]
# Using Dynamic Programming with cumulative sum
for i in range ( 1 ,N + 1 ):
dp[i][ 0 ] = 1
for i in range ( 1 ,N + 1 ):
for j in range ( 1 ,K + 1 ):
# 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
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]
ans = dp[N][K]
if K > = 1 :
ans - = dp[N][K - 1 ]
return ans
if __name__ = = "__main__" :
N = 4
K = 2
print (numberOfPermWithKInversions(N, K))
|
// C# program to find number of permutation // with K inversions using System;
using System.Collections.Generic;
class Program {
static int numberOfPermWithKInversions( int N, int K)
{
var dp = new int [N + 1, 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;
}
static void Main( string [] args)
{
int N = 4;
int K = 2;
Console.WriteLine(
numberOfPermWithKInversions(N, K));
}
} |
function numberOfPermWithKInversions(N, K) {
const List1 = K + 1;
const List2 = N + 1;
const dp = Array.from(Array(List2), () => new Array(List1).fill(0));
// Using Dynamic Programming with cumulative sum
for (let i = 1; i <= N; i++) {
dp[i][0] = 1;
}
for (let i = 1; i <= N; i++) {
for (let 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
let 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]
let ans = dp[N][K];
if (K >= 1) {
ans -= dp[N][K-1];
}
return ans;
} const N = 4; const K = 2; console.log(numberOfPermWithKInversions(N, K)); |
5
Time Complexity: O(N*K)
Space Complexity: O(N*K)