📜  数组中的明显反转

📅  最后修改于: 2021-04-22 03:12:41             🧑  作者: Mango

给定一个数组arr [] ,任务是找到该数组的总有效反转计数。如果arr [i]> 2 * arr [j]i 两个元素arr [i]arr [j]构成一个显着的反演。

例子:

先决条件:计算倒数

方法:

  • 查找倒置的基本思想将基于上述前提,并使用修改后的合并排序的分而治之方法。
  • 可以计算出左半部分和右半部分的显着倒置次数。用索引(i,j)包括显着倒置的计数,以使i在左半部分,而j在右半部分,然后将所有三个数相加以获得总的显着倒置计数。
  • 可以修改上述链接中使用的方法,以在合并步骤中执行左半边和右半边的两次遍历。在第一遍中,计算合并数组中有效反转计数的数量。对于arr [i]> 2 * arr [j],如果在左数组中的任何索引i,则在左数组中的第i个索引左侧的所有元素也将导致显着的反转计数。增量j。否则增加i。
  • 第二遍将是构造合并数组。这里需要两次通过,因为在正常的反转计数中,两次通过会将i和j移动到相同的点,因此可以合并,但是在这种情况下不正确。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
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..


输出:
3