Count inversions in an array (Using BIT in JavaScript)

Inversion Count for an array indicates – how far (or close) the array is from being sorted. If the array is already sorted then the inversion count is 0. If the array is sorted in the reverse order that inversion count is the maximum.
Two elements a[i] and a[j] form an inversion if a[i] > a[j] and i < j. For simplicity, we may assume that all elements are unique.
Example:

Input: arr[] = {8, 4, 2, 1} Output: 6 Explanation: Given array has six inversions: (8,4), (4,2), (8,2), (8,1), (4,1), (2,1). Input: arr[] = {3, 1, 2} Output: 2 Explanation: Given array has two inversions: (3,1), (3,2).

Solution using BIT of size Θ(maxElement):

  • Approach: Traverse through the array and for every index find the number of smaller elements on its right side of the array. This can be done using BIT. Sum up the counts for all indexes in the array and print the sum.

  • Background on BIT:

    1. BIT basically supports two operations for an array arr[] of size n:
    2. Sum of elements till arr[i] in O(Log n) time.
    3. Update an array element in O(Log n) time.
    4. BIT is implemented using an array and works in form of trees. Note that there are two ways of looking at BIT as a tree.
    5. The sum operation where parent of index x is “x – (x & -x)”.
    6. The update operation where parent of index x is “x + (x & -x)”.
  • Algorithm:

    1. Create a BIT, to find the count of the smaller elements in the BIT for a given number and also a variable result = 0.
    2. Traverse the array from end to start.
    3. For every index check how many numbers less than the current element are present in BIT and add it to the result
    4. To get the count of smaller elements, getSum() of BIT is used.
    5. In his basic idea, BIT is represented as an array of size equal to maximum element plus one. So that elements can be used as an index.
    6. After that we add the current element to the BIT[] by doing an update operation that updates the count of the current element from 0 to 1, and therefore updates ancestors of the current element in BIT .
  • Implementation

  • Javascript

<script>

// javascript program to count inversions

// using Binary Indexed Tree

// Returns sum of arr[0..index].

// This function assumes that the

// array is preprocessed and partial

// sums of array elements are stored

// in BITree.

function getSum(BITree , index)

{

var sum = 0; // Initialize result

// Traverse ancestors of BITree[index]

while (index > 0)

{

// Add current element of BITree to sum

sum += BITree[index];

// Move index to parent node in getSum View

index -= index & (-index);

}

return sum;

}

// Updates a node in Binary Index

// Tree (BITree) at given index

// in BITree. The given value 'val'

// is added to BITree[i] and all

// of its ancestors in tree.

function updateBIT(BITree , n, index , val)

{

// Traverse all ancestors and add 'val'

while (index <= n)

{

// Add 'val' to current node of BI Tree

BITree[index] += val;

// Update index to that of parent in update View

index += index & (-index);

}

}

// Returns inversion count arr[0..n-1]

function getInvCount(arr , n)

{

var invcount = 0; // Initialize result

// Find maximum element in arr

var maxElement = 0;

for (i = 0; i < n; i++)

if (maxElement < arr[i])

maxElement = arr[i];

// Create a BIT with size equal to

// maxElement+1 (Extra one is used so

// that elements can be directly be

// used as index)

var BIT = Array.from({length: maxElement + 1}, (_, i) => 0);

for (i = 1; i <= maxElement; i++)

BIT[i] = 0;

// Traverse all elements from right.

for (i = n - 1; i >= 0; i--)

{

// Get count of elements smaller than arr[i]

invcount += getSum(BIT, arr[i] - 1);

// Add current element to BIT

updateBIT(BIT, maxElement, arr[i], 1);

}

return invcount;

}

// Driver code

var arr = [8, 4, 2, 1];

var n = arr.length;

document.write( "Number of inversions are : " +

getInvCount(arr,n));

</script>

  • Output:

Number of inversions are : 6

  • Complexity Analysis:
    • Time Complexity :- The update function and getSum function runs for O(log(maximumelement)). The getSum function has to be run for every element in the array. So overall time complexity is : O(nlog(maximumelement)).
    • Auxiliary space : O(maxElement), space required for the BIT is an array of the size of the largest element.