Significant Inversions in an Array

Given an array arr[], the task is to finds the total significant inversion count for the array. Two elements arr[i] and arr[j] form a significant inversion if arr[i] > 2 * arr[j] and i < j.

Examples:

Input: arr[] = { 1, 20, 6, 4, 5 }
Output: 3
Significant inversion pair are (20, 6), (20, 5) and (20, 4).



Input: arr[] = { 1, 20 }
Output: 0

Prerequisite: Counting Inversions

Approach:

  • The basic idea to find inversions will be based on the above prerequisite, using the Divide and Conquer approach of the modified merge sort.
  • The number of significant inversions in the left half and the right half can be counted. Including the count of significant inversion with index (i, j) such that i is in the left half and j is in the right half and then add all three to get the total significant inversion count.
  • Approach used in the above link can be modified to perform two passes of left and right half during merge step. In first pass, calculate the number of significant inversion count in the merged array. For any index i in left array if arr[i] > 2 * arr[j], then all the elements to the left of ith index in left array will also contribute to significant inversion count. Increment j. Otherwise increment i.
  • Second pass will be to construct the merged array. Here two passes are required because in the normal inversion count, the two passes would move i and j at the same points so can be combined, but that is not true in this case.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
  
int _mergeSort(int arr[], int temp[], int left, int right);
int merge(int arr[], int temp[], int left, int mid, int right);
  
// Function that sorts the input array
// and returns the number of inversions
// in the array
int mergeSort(int arr[], int array_size)
{
    int temp[array_size];
    return _mergeSort(arr, temp, 0, array_size - 1);
}
  
// Recursive function that sorts the input
// array and returns the number of
// inversions in the array
int _mergeSort(int arr[], int temp[], int left, int right)
{
    int mid, inv_count = 0;
    if (right > left) {
  
        // Divide the array into two parts and
        // call _mergeSortAndCountInv()
        // for each of the parts
        mid = (right + left) / 2;
  
        // Inversion count will be sum of the
        // inversions in the left-part, the right-part
        // and the number of inversions in merging
        inv_count = _mergeSort(arr, temp, left, mid);
        inv_count += _mergeSort(arr, temp, mid + 1, right);
  
        // Merge the two parts
        inv_count += merge(arr, temp, left, mid + 1, right);
    }
    return inv_count;
}
  
// Function that merges the two sorted arrays
// and returns the inversion count in the arrays
int merge(int arr[], int temp[], int left,
          int mid, int right)
{
    int i, j, k;
    int inv_count = 0;
  
    // i is the index for the left subarray
    i = left;
  
    // j is the index for the right subarray
    j = mid;
  
    // k is the index for the resultant
    // merged subarray
    k = left;
  
    // First pass to count number
    // of significant inversions
    while ((i <= mid - 1) && (j <= right)) {
        if (arr[i] > 2 * arr[j]) {
            inv_count += (mid - i);
            j++;
        }
        else {
            i++;
        }
    }
  
    // i is the index for the left subarray
    i = left;
  
    // j is the index for the right subarray
    j = mid;
  
    // k is the index for the resultant
    // merged subarray
    k = left;
  
    // Second pass to merge the two sorted arrays
    while ((i <= mid - 1) && (j <= right)) {
        if (arr[i] <= arr[j]) {
            temp[k++] = arr[i++];
        }
        else {
            temp[k++] = arr[j++];
        }
    }
  
    // Copy the remaining elements of the left
    // subarray (if there are any) to temp
    while (i <= mid - 1)
        temp[k++] = arr[i++];
  
    // Copy the remaining elements of the right
    // subarray (if there are any) to temp
    while (j <= right)
        temp[k++] = arr[j++];
  
    // Copy back the merged elements to
    // the original array
    for (i = left; i <= right; i++)
        arr[i] = temp[i];
  
    return inv_count;
}
  
// Driver code
int main()
{
    int arr[] = { 1, 20, 6, 4, 5 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    cout << mergeSort(arr, n);
  
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the above approach 
class GFG 
{
          
    // Function that sorts the input array 
    // and returns the number of inversions 
    // in the array 
    static int mergeSort(int arr[], int array_size) 
    
        int temp[] = new int[array_size]; 
        return _mergeSort(arr, temp, 0, array_size - 1); 
    
      
    // Recursive function that sorts the input 
    // array and returns the number of 
    // inversions in the array 
    static int _mergeSort(int arr[], int temp[],
                          int left, int right) 
    
        int mid, inv_count = 0
        if (right > left) 
        
      
            // Divide the array into two parts and 
            // call _mergeSortAndCountInv() 
            // for each of the parts 
            mid = (right + left) / 2
      
            // Inversion count will be sum of the 
            // inversions in the left-part, the right-part 
            // and the number of inversions in merging 
            inv_count = _mergeSort(arr, temp, left, mid); 
            inv_count += _mergeSort(arr, temp, mid + 1, right); 
      
            // Merge the two parts 
            inv_count += merge(arr, temp, left, 
                               mid + 1, right); 
        
        return inv_count; 
    
      
    // Function that merges the two sorted arrays 
    // and returns the inversion count in the arrays 
    static int merge(int arr[], int temp[], int left, 
                                int mid, int right) 
    
        int i, j, k; 
        int inv_count = 0
      
        // i is the index for the left subarray 
        i = left; 
      
        // j is the index for the right subarray 
        j = mid; 
      
        // k is the index for the resultant 
        // merged subarray 
        k = left; 
      
        // First pass to count number 
        // of significant inversions 
        while ((i <= mid - 1) && (j <= right)) 
        
            if (arr[i] > 2 * arr[j]) 
            
                inv_count += (mid - i); 
                j++; 
            
            else 
            
                i++; 
            
        
      
        // i is the index for the left subarray 
        i = left; 
      
        // j is the index for the right subarray 
        j = mid; 
      
        // k is the index for the resultant 
        // merged subarray 
        k = left; 
      
        // Second pass to merge the two sorted arrays 
        while ((i <= mid - 1) && (j <= right))
        
            if (arr[i] <= arr[j]) 
            
                temp[k++] = arr[i++]; 
            
            else 
            
                temp[k++] = arr[j++]; 
            
        
      
        // Copy the remaining elements of the left 
        // subarray (if there are any) to temp 
        while (i <= mid - 1
            temp[k++] = arr[i++]; 
      
        // Copy the remaining elements of the right 
        // subarray (if there are any) to temp 
        while (j <= right) 
            temp[k++] = arr[j++]; 
      
        // Copy back the merged elements to 
        // the original array 
        for (i = left; i <= right; i++) 
            arr[i] = temp[i]; 
      
        return inv_count; 
    
      
    // Driver code 
    public static void main (String[] args) 
    
        int arr[] = { 1, 20, 6, 4, 5 }; 
        int n = arr.length; 
      
        System.out.println(mergeSort(arr, n)); 
    
}
  
// This code is contributed by AnkitRai01

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation of the approach
  
# Function that sorts the input array
# and returns the number of inversions
# in the array
def mergeSort(arr, array_size):
    temp = [0 for i in range(array_size)]
    return _mergeSort(arr, temp, 0
                      array_size - 1)
  
# Recursive function that sorts the input
# array and returns the number of
# inversions in the array
def _mergeSort(arr, temp, left, right):
    mid, inv_count = 0, 0
    if (right > left):
  
        # Divide the array into two parts and
        # call _mergeSortAndCountInv()
        # for each of the parts
        mid = (right + left) // 2
  
        # Inversion count will be sum of the
        # inversions in the left-part, the right-part
        # and the number of inversions in merging
        inv_count = _mergeSort(arr, temp, left, mid)
        inv_count += _mergeSort(arr, temp,
                                mid + 1, right)
  
        # Merge the two parts
        inv_count += merge(arr, temp, left, 
                           mid + 1, right)
    return inv_count
  
# Function that merges the two sorted arrays
# and returns the inversion count in the arrays
def merge(arr, temp, left,mid, right):
    inv_count = 0
  
    # i is the index for the left subarray
    i = left
  
    # j is the index for the right subarray
    j = mid
  
    # k is the index for the resultant
    # merged subarray
    k = left
  
    # First pass to count number
    # of significant inversions
    while ((i <= mid - 1) and (j <= right)):
        if (arr[i] > 2 * arr[j]):
            inv_count += (mid - i)
            j += 1
        else:
            i += 1
  
    # i is the index for the left subarray
    i = left
  
    # j is the index for the right subarray
    j = mid
  
    # k is the index for the resultant
    # merged subarray
    k = left
  
    # Second pass to merge the two sorted arrays
    while ((i <= mid - 1) and (j <= right)):
        if (arr[i] <= arr[j]):
            temp[k] = arr[i]
            i, k = i + 1, k + 1
        else:
            temp[k] = arr[j]
            k, j = k + 1, j + 1
  
    # Copy the remaining elements of the left
    # subarray (if there are any) to temp
    while (i <= mid - 1):
        temp[k] = arr[i]
        i, k = i + 1, k + 1
  
    # Copy the remaining elements of the right
    # subarray (if there are any) to temp
    while (j <= right):
        temp[k] = arr[j]
        j, k = j + 1, k + 1
  
    # Copy back the merged elements to
    # the original array
    for i in range(left, right + 1):
        arr[i] = temp[i]
  
    return inv_count
  
# Driver code
arr = [1, 20, 6, 4, 5]
n = len(arr)
  
print(mergeSort(arr, n))
  
# This code is contributed by Mohit Kumar

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of the above approach 
using System;
  
class GFG 
{
          
    // Function that sorts the input array 
    // and returns the number of inversions 
    // in the array 
    static int mergeSort(int []arr, 
                         int array_size) 
    
        int []temp = new int[array_size]; 
        return _mergeSort(arr, temp, 0, 
                          array_size - 1); 
    
      
    // Recursive function that sorts the input 
    // array and returns the number of 
    // inversions in the array 
    static int _mergeSort(int []arr, int []temp,
                          int left, int right) 
    
        int mid, inv_count = 0; 
        if (right > left) 
        
      
            // Divide the array into two parts and 
            // call _mergeSortAndCountInv() 
            // for each of the parts 
            mid = (right + left) / 2; 
      
            // Inversion count will be sum of the 
            // inversions in the left-part, the right-part 
            // and the number of inversions in merging 
            inv_count = _mergeSort(arr, temp, left, mid); 
            inv_count += _mergeSort(arr, temp,
                                    mid + 1, right); 
      
            // Merge the two parts 
            inv_count += merge(arr, temp, left, 
                               mid + 1, right); 
        
        return inv_count; 
    
      
    // Function that merges the two sorted arrays 
    // and returns the inversion count in the arrays 
    static int merge(int []arr, int []temp, int left, 
                                int mid, int right) 
    
        int i, j, k; 
        int inv_count = 0; 
      
        // i is the index for the left subarray 
        i = left; 
      
        // j is the index for the right subarray 
        j = mid; 
      
        // k is the index for the resultant 
        // merged subarray 
        k = left; 
      
        // First pass to count number 
        // of significant inversions 
        while ((i <= mid - 1) && (j <= right)) 
        
            if (arr[i] > 2 * arr[j]) 
            
                inv_count += (mid - i); 
                j++; 
            
            else
            
                i++; 
            
        
      
        // i is the index for the left subarray 
        i = left; 
      
        // j is the index for the right subarray 
        j = mid; 
      
        // k is the index for the resultant 
        // merged subarray 
        k = left; 
      
        // Second pass to merge the two sorted arrays 
        while ((i <= mid - 1) && (j <= right))
        
            if (arr[i] <= arr[j]) 
            
                temp[k++] = arr[i++]; 
            
            else
            
                temp[k++] = arr[j++]; 
            
        
      
        // Copy the remaining elements of the left 
        // subarray (if there are any) to temp 
        while (i <= mid - 1) 
            temp[k++] = arr[i++]; 
      
        // Copy the remaining elements of the right 
        // subarray (if there are any) to temp 
        while (j <= right) 
            temp[k++] = arr[j++]; 
      
        // Copy back the merged elements to 
        // the original array 
        for (i = left; i <= right; i++) 
            arr[i] = temp[i]; 
      
        return inv_count; 
    
      
    // Driver code 
    public static void Main () 
    
        int []arr = { 1, 20, 6, 4, 5 }; 
        int n = arr.Length; 
      
        Console.WriteLine(mergeSort(arr, n)); 
    
}
  
// This code is contributed by anuj_67..

chevron_right


Output:

3


My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

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.