Open In App

Significant Inversions in an Array

Improve
Improve
Like Article
Like
Save
Share
Report

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:
Significant inversion pair are (20, 6), (20, 5) and (20, 4).
Input: arr[] = { 1, 20 } 
Output:

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++




// 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;
}


Java




// 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


Python3




# 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


C#




// 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..


Javascript




<script>
    // Javascript implementation of the above approach
     
    // Function that sorts the input array
    // and returns the number of inversions
    // in the array
    function mergeSort(arr, array_size)
    {
        let temp = new Array(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
    function _mergeSort(arr, temp, left, right)
    {
        let mid, inv_count = 0;
        if (right > left)
        {
       
            // Divide the array into two parts and
            // call _mergeSortAndCountInv()
            // for each of the parts
            mid = parseInt((right + left) / 2, 10);
       
            // 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
    function merge(arr, temp, left, mid, right)
    {
        let i, j, k;
        let 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;
    }
     
    let arr = [ 1, 20, 6, 4, 5 ];
    let n = arr.length;
 
    document.write(mergeSort(arr, n));
     
    // This code is contributed by mukesh07.
</script>


Output: 

3

 

Time Complexity: O(n * log(n))
Auxiliary Space: O(n), where n is the size of the given array.



Last Updated : 21 Dec, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads