需要帮助找出我在这个反转算法中做错了什么(基于合并排序)

Need help on figuring out what I did wrong in this Inversions algorithm (based on merge sort)

本文关键字:什么 错了 于合并 排序 合并 算法 帮助      更新时间:2023-10-16

目标是在整数数组中找到反转的数量。例如

给定 : (1,3,5,2,4,6)

反转是:(3,2)、(5,4)、(5,2)。

也就是说,总共三次反转。O(n^2) 解决方案需要两个 for 循环,但对于大型输入数组来说需要太长时间。由于合并排序需要 O(n(log(n))) 时间,因此在这种情况下实现它是有意义的。

通过分而治之的方法,我们可以实现O(n(log(n)))。解决方案是取反转的总和。反转如下(对于大小为"n"的输入数组):

左反转,如果 i,j <= n/2

右反转,如果 i,j> n/2

拆分反转,如果 i <= n/2

注意:拆分反转是在 arr[i]> arr[j] 和 i

基于上述主张,这是我编写的以下算法(其中我首先编写了合并排序的算法,然后相应地对其进行了调整以返回反转的数量),我获得了错误的输出。我无法弄清楚我哪里出错了。

(如有需要,请询问其他信息。我已经坚持了一段时间了)。

#include<iostream>
#include<vector>
using namespace std;
int merge(vector <int> & arr, int l, int m , int r)
{
    int i,j,k;
    int count = 0;
    int n1, n2;
    n1=m-l+1;
    n2=r-m;
    //temporary arrays to store the elements.
    int L[n1];
    int R[n2];
    for (int i = 0; i < n1; ++i)
    {
        L[i]=arr[l+i];
    }
    for (int j = 0; j < n2; ++j)
    {
        R[j]=arr[m+1+j];
    }
    i=0;
    j=0;
    k=l;
    while(i<n1 && j<n2)
    {
        if (L[i]<R[j])
        {
            arr[k]=L[i];
            i++;
        }
        else
        {
            arr[k]=R[j];
            j++;
            count=count+(m-i);
        }
        k++;
    }
    while(i<n1)
    {
        arr[k]=L[i];
        i++;
        k++;
    }
    while(j<n2)
    {
        arr[k]=R[j];
        j++;
        k++;
    }
    return count;
}
int mergeSort(vector <int> & arr, int l, int r)
{
    int m;
    int count=0;
    /*
     if (l<r)
     {
     m=l+(r-l)/2;

     mergeSort(arr, l, m);//used to recursively sort the left half of the array
     mergeSort(arr,m+1,r);//used to recursively sort the right half of the array
     merge(arr,l,m,r);//merges both arrays together.
     }
     */

    if(l<r)
    {
        m = (l + r) / 2;
        count =
        (mergeSort(arr, l, m) +
         mergeSort(arr, m+1, r) +
         merge(arr, l, m, r));
        return count;
    }
    else
        return 0;
}

void printArray(vector <int> A, int size)
{
    for (int i = 0; i < size; ++i)
    {
        cout<<A[i]<< " ";
    }
    cout<<endl;
}
int main()
{
    int n;
    cin>>n;
    //int arr[n];
    vector<int> arr(n);
    int i;

    for (i=0; i<n; i++) {
        cin>>arr[i];
    }
    /*
     cout<<"the given array is : "<<endl;
     printArray(arr, n);
     */        
    cout<<"the number of inversions are : "<<endl;
    cout<< mergeSort(arr, 0, n - 1) <<endl;
    /*        
     cout<<"the sorted array is : "<<endl;
     printArray(arr, n);
     */      
    return 0;
}

测试用例:

案例-1

输入:

(对于 n = 6)

1 3 5 2 4 6

预期输出: 3

获得的输出: 1

案例-2

输入:

(对于 n = 15)

9 12 3 1 6 8 2 5 14 13 11 7 10 4 0

预期输出: 56

获得的输出: 125

问题在于计算我们在每一步中获得的反转次数。让我们来看看合并:我们有两个数组 L 和 R,在每次迭代中,我们查看每个数组中的第一个数字(因为它们已经排序):

1). L[i] <= R[j].这意味着 L[i] 不会用 R 中的一些剩余元素创建新的反转。

2). L[i]> R[J].这意味着 R[j] 将与 L[i], L[i + 1], L[i + 2], ..., L[n1 - 1] 产生反转。从我所看到的,您的错误在于计数计算。您添加 (m - i) 而不是 (n1 - i)。我看到的另一个错误是计数类型。如果你假设大小很大(~10^5),你需要一些更大的类型来存储你的值。

希望这有所帮助。