Count Inversions in an array in Java

An array is given that contains integers. The task is to find the total count inversions in the given array. Total count inversions is a number that indicates how close or far the given array is from being sorted. For the sorted array, the inversion count is 0. If the array is sorted in the reverse order, then the inversion count is the maximum for that array. See the following examples.

Example 1:

Input

int inArr[] = {7, 4, 9, 1, 3, 5, 0, 6, 2, 8}

Output: 24

Explanation: The given array has the following inversions:

(7, 4), (7, 1), (7, 3), (7, 5), (7, 0), (7, 6), (7, 2), (4, 1), (4, 3), (4, 0), (4, 2), (9, 1), (9, 3), (9, 5), (9, 0), (9, 6), (9, 2), (9, 8), (1, 0), (3, 0), (3, 2), (5, 0), (5, 2), (6, 2). Thus, the total count inversion is 24.

Example 2:

Input

int inArr[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}

Output: 45

Explanation: All the elements are arranged in strictly decreasing order. So, this time we will have the maximum count inversion. The inversions are:

(9, 8), (9, 7), (9, 6), (9, 5), (9, 4), (9, 3), (9, 2), (9, 1), (9, 0), (8, 7), (8, 6), (8, 5), (8, 4), (8, 3), (8, 2), (8, 1), (8, 0), (7, 6), (7, 5), (7, 4), (7, 3), (7, 2), (7, 1), (7, 0), (6, 5), (6, 4), (6, 3), (6, 2), (6, 1), (6, 0), (5, 4), (5, 3), (5, 2), (5, 1), (5, 0), (4, 3), (4, 2), (4, 1), (4, 0), (3, 2), (3, 1), (3, 0), (2, 1), (2, 0), (1, 0), and their count is (9 * (9 + 1)) / 2 = 45.

Example 3:

Input

int inArr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

Output: 0

Explanation: The elements are arranged in increasing order. Thus, no small elements exist on the right side, making the inversion count 0.

Example 4:

Input

int inArr[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4}

Output: 0

Explanation: All the elements of the input array are constant, i.e., of the same value. Thus, no small element exists on the right side of the input array. Hence, the inversion count is 0.

Approach: Using Nested Loop

In this approach, we will be nesting two for-loops. The outer loop picks the element from the input array (consider it as the current element). The inner loop starts from the element next to the current element and goes all the way to the end. In the inner loop, compare the elements pointed by the inner loop variable with the current element. If it is small, increase the inversion count by 1; otherwise, do not increase the inversion count.

FileName: CountInversion.java

Output:

```For the input array:
7 4 9 1 3 5 0 6 2 8
The total inversion count of the input array is: 24

For the input array:
9 8 7 6 5 4 3 2 1 0
The total inversion count of the input array is: 45

For the input array:
0 1 2 3 4 5 6 7 8 9
The total inversion count of the input array is: 0

For the input array:
4 4 4 4 4 4 4 4 4 4
The total inversion count of the input array is: 0
```

Complexity Analysis: Since the program uses nested loops, the time complexity of the program is O(N2). The program is not using any extra space. Therefore, the space complexity of the program is constant, i.e., O(1).

Approach: Enhanced Merge Sort

The approach is to use the enhanced merge sort. In this approach, we will first split the input array into two subarrays, and then we will count the inversion in the first and the second subarrays. After that, we will count the inversions after merging the subarrays. The total count gives the answer. We will be splitting the input array into subarrays recursively. The steps to find the solution is mentioned below.

Step 1: Split the input array into two almost equal or equal halves in each recursive step unless the base case is achieved. The base case of the recursion is reached when there is only one element in the given half.

Step 2: Create a method merge() that counts the total inversions number when the two halves of the input array are merged. Create two indices j and k, j is the index of the first half, and k is the index dedicated for the second half. if inArr[j] is more than the inArr[k], then there are the (mid - j) inversions. It is because the right and the left subarrays are sorted, so in the left-subarray all of the remaining elements inArr[j + 1], inArr[j + 2] … inArr[mid]) will be more than the inArr[k].

Step 3: Also, create a recursive method for dividing the input array into two halves and computing the answer by adding the inversions number of the first half, of the second half and the inversions number by merging the two halves.

Step 4: Display the total count.

Implementation

Observe the implementation of the above steps.

FileName: CountInversion1.java

Output:

```For the input array:
7 4 9 1 3 5 0 6 2 8
The total inversions count is: 24

For the input array:
9 8 7 6 5 4 3 2 1 0
The total inversions count is: 45

For the input array:
0 1 2 3 4 5 6 7 8 9
The total inversions count is: 0

For the input array:
4 4 4 4 4 4 4 4 4 4
The total inversions count is: 0
```

Complexity Analysis: The merge sort takes O(n x log(n)) time. Therefore, the time complexity of the program is O(n x log(n)). The space complexity of the program is O(n), as the auxiliary arrays are used for storing the left and the right sub-array, where n is the total number of elements present in the input array.

Approach: Using Self Balancing Tree

Algorithm

Step 1: Create an AVL tree. Also, add a property in every node of the tree that each node will contain information about the size of its subtree.

Step 2: Traverse the input array from the last to the beginning.

Step 3: For each element, put that element in the self-balancing tree (AVL tree).

Step 4: The number of nodes that are larger than the current element can easily be computed by checking the size of the right sub-tree (number of right children). Thus, it is sure that the number of elements in the right subtree of the current node has an index less than the current element (as we are traversing the input array from end to beginning). Also, the right children have a larger value than the current element (property of an AVL tree). Therefore, the inversion criteria are satisfied. Hence, increase the count by the right-subtree size of the node that is currently inserted.

Step 5: Display the count.

FileName: CountInversion2.java

Output:

```For the input array:
7 4 9 1 3 5 0 6 2 8
The total inversions count is: 24

For the input array:
9 8 7 6 5 4 3 2 1 0
The total inversions count is: 45

For the input array:
0 1 2 3 4 5 6 7 8 9
The total inversions count is: 0

For the input array:
4 4 4 4 4 4 4 4 4 4
The total inversions count is: 0
```

Complexity Analysis: The time, as well as the space complexity, of the program, is the same as the previous program.

Approach: Using Binary Indexed Tree

Using Binary Indexed Tree also, one can achieve the desired result. Observe the following algorithm.

Algorithm

Using Binary Indexed Tree also, one can achieve the desired result. Observe the following algorithm.

Step 1: Create a Binary Indexed Tree for finding the number of the lesser elements for a number. Also, create variable res = 0.

Step 2: Traverse the input array from the last to the beginning.

Step 3: For each index, find out the total number of elements that are less than the current element and update the result by adding it.

Step 4: Create a method retrieveSum() for getting the number of smaller elements.

Step 5: Add the current element to the array BIT[] by performing the update operation that updates the current element count from 0 to 1, and hence updates the current element ancestors in the Binary Indexed Tree.

FileName: CountInversion3.java

Output:

```For the input array:
7 4 9 1 3 5 0 6 2 8
The total inversions count is: 24

For the input array:
9 8 7 6 5 4 3 2 1 0
The total inversions count is: 45

For the input array:
0 1 2 3 4 5 6 7 8 9
The total inversions count is: 0

For the input array:
4 4 4 4 4 4 4 4 4 4
The total inversions count is: 0
```

Complexity Analysis: The time, as well as the space complexity, of the program, is the same as the previous program.