文章目录

  • Question
  • Ideas
  • Code


Question

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

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

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

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

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

数据范围
1≤n≤100000

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

输入样例:
6
2 3 4 5 6 1
输出样例:
5

Ideas

利用归并的过程来计算逆序对的数量
总的来看逆序对有三种
在左区间内,在右区间内,横跨左右两个区间
单独在左右区间的可以直接递归处理,因为递归排序使得每个区间都是有序的
横跨左右两个区间的需要计算 res += mid - i + 1

Code

#include <iostream>

using namespace std;
const int N = 1e5 + 10;
typedef long long LL;

int q[N], tem[N];

LL merge_sort(int q[], int l, int r)
{
    if (l >= r) return 0;
    
    int mid = l + r >> 1;
    
    LL res = merge_sort(q, l, mid) + merge_sort(q, mid + 1, r);
    
    int i = l, j = mid + 1, k = 0;
    
    while(i <= mid && j <= r)
    {
        if (q[i] <= q[j]) tem[k++] = q[i++];
        else
        {
            tem[k++] = q[j++];
            res += mid - i + 1;
        }
    }
    
    while(i <= mid) tem[k++] = q[i++];
    while(j <= r) tem[k++] = q[j ++];
    
    for (int i = 0; i < k; i ++) q[l+i] = tem[i];
    
    return res;
}

int main()
{
    int n;
    scanf("%d", &n);
    
    for (int i = 0; i < n; i ++) scanf("%d", &q[i]);
    
    printf("%lld", merge_sort(q, 0, n - 1));
    
    return 0;
}
def merge_sort(q, l, r):
    if l >= r:
        return 0
    
    mid = l + r >> 1
    
    res = merge_sort(q, l, mid) + merge_sort(q, mid + 1, r)
    
    i, j = l, mid + 1
    tem = []

    while i <= mid and j <= r:
        if q[i] <= q[j]:
            tem.append(q[i])
            i += 1
        else:
            tem.append(q[j])
            j += 1
            res += mid - i + 1
    
    while i <= mid:
        tem.append(q[i])
        i += 1
    
    while j <= r:
        tem.append(q[j])
        j += 1
    
    q[l:r+1] = tem
    return res
    
if __name__ == '__main__':
    n = int(input())
    q = list(map(int,input().strip().split()))
    
    print(merge_sort(q, 0, n - 1))

788. 逆序对的数量(C++和Python3)——2023.5.2打卡_c++