Count inversions of size k in a given array

Given an array of n distinct integers a_{1}, a_{2}, ..., a_{n} and an integer k. Find out the number of sub-sequences of a such that a_{i_{1}} > a_{i_{2}} > ... > a_{i_{k}}, and 1 <= i_{1} < i_{2} < ... < i_{k} <= n. In other words output the total number of inversions of length k.

Examples:

Input : a[] = {9, 3, 6, 2, 1}, k = 3        
Output : 7
The seven inversions are {9, 3, 2}, {9, 3, 1}, 
{9, 6, 2}, {9, 6, 1}, {9, 2, 1}, {3, 2, 1} and
{6, 2, 1}.

Input : a[] = {5, 6, 4, 9, 2, 7, 1}, k = 4
Output : 2
The two inversions are {5, 4, 2, 1}, {6, 4, 2, 1}.

We have already discussed counting inversion of length three here. This post will generalise the approach using Binary Indexed Tree and Counting inversions using BIT. More on Binary Indexed Trees can be found from the actual paper that Peter M. Fenwick published, here.



1. To begin with, we first convert the given array to a permutation of elements 1, 2, 3, ..., n (Note that this is always possible since the elements are distinct).
2. The approach is to maintain a set of k Fenwick Trees. Let it be denoted by bit[k][n] where bit[l][x], keeps track of the number of l – length sub-sequences that start with x .
3. We iterate from the end of the converted array to the beginning. For every converted array element x, we update the Fenwick tree set, as: For each 1 <= l <= k, each sub-sequence of length l that start with a number less than x is also a part of sequences of length l+1 .
The final result is found by sum of occurences of (k, n).

The implementation is discussed below:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to count inversions of size k using
// Binary Indexed Tree
#include <bits/stdc++.h>
using namespace std;
  
// It is beneficial to declare the 2D BIT globally 
// since passing it into functions will create 
// additional overhead
const int K = 51;
const int N = 100005;
int BIT[K][N] = { 0 };
  
// update function. "t" denotes the t'th Binary 
// indexed tree
void updateBIT(int t, int i, int val, int n)
{
    // Traversing the t'th BIT
    while (i <= n) {
        BIT[t][i] = BIT[t][i] + val;
        i = i + (i & (-i));
    }
}
  
// function to get the sum.
// "t" denotes the t'th Binary indexed tree
int getSum(int t, int i)
{
    int res = 0;
  
    // Traversing the t'th BIT
    while (i > 0) {
        res = res + BIT[t][i];
        i = i - (i & (-i));
    }
    return res;
}
  
// Converts an array to an array with values from 1 to n
// and relative order of smaller and greater elements 
// remains same.  For example, {7, -90, 100, 1} is
// converted to {3, 1, 4, 2 }
void convert(int arr[], int n)
{
    // Create a copy of arr[] in temp and sort 
    // the temp array in increasing order
    int temp[n];
    for (int i = 0; i < n; i++)
        temp[i] = arr[i];
    sort(temp, temp + n);
  
    // Traverse all array elements
    for (int i = 0; i < n; i++) {
  
        // lower_bound() Returns pointer to the 
        // first element greater than or equal
        // to arr[i]
        arr[i] = lower_bound(temp, temp + n, 
                           arr[i]) - temp + 1;
    }
}
  
// Returns count of inversions of size three
int getInvCount(int arr[], int n, int k)
{
    // Convert arr[] to an array with values from 
    // 1 to n and relative order of smaller and
    // greater elements remains same.  For example, 
    // {7, -90, 100, 1} is converted to {3, 1, 4, 2 }
    convert(arr, n);
  
    // iterating over the converted array in 
    // reverse order.
    for (int i = n - 1; i >= 0; i--) {
        int x = arr[i];
  
        // update the BIT for l = 1
        updateBIT(1, x, 1, n);
  
        // update BIT for all other BITs
        for (int l = 1; l < k; l++) {
            updateBIT(l + 1, x, getSum(l, x - 1), n);
        }
    }
  
    // final result
    return getSum(k, n);
}
  
// Driver program to test above function
int main()
{
    int arr[] = { 5, 6, 4, 9, 3, 7, 2, 1 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 4;
    cout << "Inversion Count : " << getInvCount(arr, n, k);
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program to count 
// inversions of size k using
// Binary Indexed Tree
import java.io.*;
import java.util.Arrays;
import java.util.ArrayList;
import java.lang.*;
import java.util.Collections;
  
class GFG
{
  
// It is beneficial to declare
// the 2D BIT globally since 
// passing it into functions 
// will create additional overhead
static int K = 51;
static int N = 100005;
static int BIT[][] = new int[K][N];
  
// update function. "t" denotes 
// the t'th Binary indexed tree
static void updateBIT(int t, int i,
                      int val, int n)
{
     
    // Traversing the t'th BIT
    while (i <= n)
    {
        BIT[t][i] = BIT[t][i] + val;
        i = i + (i & (-i));
    }
}
  
// function to get the sum.
// "t" denotes the t'th 
// Binary indexed tree
static int getSum(int t, int i)
{
    int res = 0;
  
    // Traversing the t'th BIT
    while (i > 0
    {
        res = res + BIT[t][i];
        i = i - (i & (-i));
    }
    return res;
}
  
// Converts an array to an 
// array with values from
// 1 to n and relative order
// of smaller and greater 
// elements remains same. 
// For example, {7, -90, 100, 1} 
// is converted to {3, 1, 4, 2 }
static void convert(int arr[], int n)
{
    // Create a copy of arr[] in 
    // temp and sort the temp
    // array in increasing order
    int temp[] = new int[n];
    for (int i = 0; i < n; i++)
        temp[i] = arr[i];
    Arrays.sort(temp);
  
    // Traverse all array elements
    for (int i = 0; i < n; i++) 
    {
  
        // lower_bound() Returns 
        // pointer to the first 
        // element greater than 
        // or equal to arr[i]
        arr[i] = Arrays.binarySearch(temp, 
                                     arr[i]) + 1;
    }
}
  
// Returns count of inversions
// of size three
static int getInvCount(int arr[], 
                       int n, int k)
{
      
    // Convert arr[] to an array 
    // with values from 1 to n and 
    // relative order of smaller 
    // and greater elements remains 
    // same. For example, {7, -90, 100, 1}
    // is converted to {3, 1, 4, 2 }
    convert(arr, n);
  
    // iterating over the converted 
    // array in reverse order.
    for (int i = n - 1; i >= 0; i--) 
    {
        int x = arr[i];
  
        // update the BIT for l = 1
        updateBIT(1, x, 1, n);
  
        // update BIT for all other BITs
        for (int l = 1; l < k; l++) 
        {
            updateBIT(l + 1, x, 
                      getSum(l, x - 1), n);
        }
    }
  
    // final result
    return getSum(k, n);
}
  
// Driver Code
public static void main(String[] args)
{
      
    int arr[] = { 5, 6, 4, 9
                  3, 7, 2, 1 };
    int n = arr.length;
    int k = 4;
    System.out.println("Inversion Count : "
                        getInvCount(arr, n, k));
}
}

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 program to count inversions 
# of size k using Binary Indexed Tree 
  
# It is beneficial to declare the 2D BIT 
# globally since passing it o functions 
# will create additional overhead 
K = 51
N = 100005
BIT = [[0 for x in range(N)] 
          for y in range(K)] 
  
# update function. "t" denotes
# the t'th Binary indexed tree 
def updateBIT(t, i, val, n): 
  
    # Traversing the t'th BIT 
    while (i <= n): 
        BIT[t][i] = BIT[t][i] + val 
        i = i + (i & (-i)) 
  
# function to get the sum. "t" denotes 
# the t'th Binary indexed tree 
def getSum(t, i):
  
    res = 0
  
    # Traversing the t'th BIT 
    while (i > 0): 
        res = res + BIT[t][i] 
        i = i - (i & (-i)) 
  
    return res 
  
# Converts an array to an array with 
# values from 1 to n and relative order 
# of smaller and greater elements remains
# same. For example, 7, -90, 100, 1 is 
# converted to 3, 1, 4, 2 
def convert( arr, n): 
  
    # Create a copy of arr[] in temp and sort 
    # the temp array in increasing order 
    temp = [0] *
    for i in range(n): 
        temp[i] = arr[i] 
    temp = sorted(temp)
    j = 1
    for i in temp:
        arr[arr.index(i)] = j
        j += 1
  
# Returns count of inversions 
# of size three 
def getInvCount(arr, n, k) :
      
    # Convert arr[] to an array with 
    # values from 1 to n and relative 
    # order of smaller and greater elements
    # remains same. For example, 7, -90, 100, 1 
    # is converted to 3, 1, 4, 2 
    convert(arr, n) 
  
    # iterating over the converted array 
    # in reverse order. 
    for i in range(n - 1, -1, -1): 
        x = arr[i] 
  
        # update the BIT for l = 1 
        updateBIT(1, x, 1, n) 
  
        # update BIT for all other BITs 
        for l in range(1, k): 
            updateBIT(l + 1, x, getSum(l, x - 1), n) 
  
    # final result 
    return getSum(k, n) 
  
# Driver code 
if __name__ =="__main__":
    arr = [5, 6, 4, 9, 3, 7, 2, 1
    n = 8
    k = 4
    print("Inversion Count :"
           getInvCount(arr, n, k))
      
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program to count 
// inversions of size k using 
// Binary Indexed Tree 
using System;
using System.Linq;
  
class GFG 
  
    // It is beneficial to declare 
    // the 2D BIT globally since 
    // passing it into functions 
    // will create additional overhead 
    static int K = 51; 
    static int N = 100005; 
    static int [,]BIT = new int[K, N]; 
  
    // update function. "t" denotes 
    // the t'th Binary indexed tree 
    static void updateBIT(int t, int i, 
                        int val, int n) 
    
  
        // Traversing the t'th BIT 
        while (i <= n) 
        
            BIT[t, i] = BIT[t, i] + val; 
            i = i + (i & (-i)); 
        
    
  
    // function to get the sum. 
    // "t" denotes the t'th 
    // Binary indexed tree 
    static int getSum(int t, int i) 
    
        int res = 0; 
  
        // Traversing the t'th BIT 
        while (i > 0) 
        
            res = res + BIT[t, i]; 
            i = i - (i & (-i)); 
        
        return res; 
    
  
    // Converts an array to an 
    // array with values from 
    // 1 to n and relative order 
    // of smaller and greater 
    // elements remains same. 
    // For example, {7, -90, 100, 1} 
    // is converted to {3, 1, 4, 2 } 
    static void convert(int []arr, int n) 
    
        // Create a copy of arr[] in 
        // temp and sort the temp 
        // array in increasing order 
        int []temp = new int[n]; 
        for (int i = 0; i < n; i++) 
            temp[i] = arr[i]; 
        Array.Sort(temp); 
  
        // Traverse all array elements 
        for (int i = 0; i < n; i++) 
        
  
            // lower_bound() Returns 
            // pointer to the first 
            // element greater than 
            // or equal to arr[i] 
            arr[i] = Array.BinarySearch(temp, 
                                        arr[i]) + 1; 
        
    
  
    // Returns count of inversions 
    // of size three 
    static int getInvCount(int []arr, 
                        int n, int k) 
    
  
        // Convert arr[] to an array 
        // with values from 1 to n and 
        // relative order of smaller 
        // and greater elements remains 
        // same. For example, {7, -90, 100, 1} 
        // is converted to {3, 1, 4, 2 } 
        convert(arr, n); 
  
        // iterating over the converted 
        // array in reverse order. 
        for (int i = n - 1; i >= 0; i--) 
        
            int x = arr[i]; 
  
            // update the BIT for l = 1 
            updateBIT(1, x, 1, n); 
  
            // update BIT for all other BITs 
            for (int l = 1; l < k; l++) 
            
                updateBIT(l + 1, x, 
                        getSum(l, x - 1), n); 
            
        
  
        // final result 
        return getSum(k, n); 
    
  
    // Driver Code 
    public static void Main(String[] args) 
    
  
        int []arr = { 5, 6, 4, 9, 
                    3, 7, 2, 1 }; 
        int n = arr.Length; 
        int k = 4; 
        Console.WriteLine("Inversion Count : "
                            getInvCount(arr, n, k)); 
    
  
// This code is contributed by PrinciRaj1992

chevron_right



Output:

Inversion Count : 11

Time Complexity \mathcal{O}(nklog(n))
Auxiliary Space \mathcal{O}(nk)

It should be noted that this is not the only approach to solve the problem of finding k-inversions. Obviously, any problem solvable by BIT is also solvable by Segment Tree. Besides, we can use Merge-Sort based algorithm, and C++ policy based data structure too. Also, at the expense of higher time complexity, Dynamic Programming approach can also be used.



My Personal Notes arrow_drop_up

I am a problem solving enthusiast and I love competitive programming

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.