📜  数组中的显着反转

📅  最后修改于: 2021-09-16 11:10:49             🧑  作者: Mango

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

先决条件:计数反转
方法:

  • 查找反转的基本思想将基于上述先决条件,使用修改后的归并排序的分而治之方法。
  • 可以统计左半边和右半边显着反转的次数。包括索引 (i, j) 的显着反转计数,使得 i 在左半部分,j 在右半部分,然后将所有三个相加得到总显着反转计数。
  • 上述链接中使用的方法可以修改为在合并步骤中执行左右半部分的两次传递。在第一遍中,计算合并数组中显着反转计数的数量。对于左数组中的任何索引 i,如果 arr[i] > 2 * arr[j],则左数组中第 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..


Javascript


输出:
3

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程