C++ 归并排序应用 逆序对数量

给定一个长度为 n
的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i
个和第 j
个元素,如果满足 i 且 a[i]>a[j]
,则其为一个逆序对;否则不是。

输入格式
第一行包含整数 n
,表示数列的长度。

第二行包含 n
个整数,表示整个数列。

输出格式
输出一个整数,表示逆序对的个数。

数据范围
1≤n≤100000

数列中的元素的取值范围 [1,109]

输入样例:
6
2 3 4 5 6 1
输出样例:
5
C++ 归并排序应用 逆序对数量_第1张图片

#include 

using namespace std;

typedef long long LL;
const int N = 100010;

int n;
int q[N];
int tmp[N];

LL nixudui(int l, int r)
{
    if(l >= r) return 0;
    
    int mid = (l + r) >> 1;
    LL res = nixudui(l, mid) + nixudui(mid + 1, r);
    
    int k = 0, i = l, j = mid + 1;
    while(i <= mid && j <= r)
    {
        if(q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
        else
        {
            tmp[k ++ ] = q[j ++ ];
            res += mid - i + 1; // 与后面的都构成逆序对
        }
    }
    while(i <= mid) tmp[k ++ ] = q[i ++ ];
    while(j <= r) tmp[k ++ ] = q[j ++ ];
    for(int i = l, j = 0; i <= r; i ++, j ++) q[i] = tmp[j];
    return res;
}

int main ()
{
    scanf("%d", &n);
    for(int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
    
    printf("%lld\n", nixudui(0, n - 1));
    
    return 0;
}

对于:res += mid - i + 1; 的解释:
在归并排序的合并过程中,我们有两个有序数组 left 和 right,它们已经各自排序好了。当我们将这两个有序数组合并成一个有序数组时,对于任意位置 i,left[i] 的右侧(即下标大于 i 的位置)的所有元素都比 left[i] 大,因为它们处于右侧,且在 left 数组中的位置更靠后。

这是因为归并排序的特性:在合并过程中,我们按顺序取两个有序数组中的元素,将较小的放入结果数组中。因此,如果 left[i] 大于 right[j],那么 right[j] 及其右侧的所有元素都大于 left[i]。

你可能感兴趣的:(力扣,算法笔记,排序,c++,排序算法,算法)