【ACWing】788. 逆序对的数量

题目地址:

https://www.acwing.com/problem/content/description/790/

给定一个长 n n n的数列,计算其逆序对数量。

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

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

数据范围:
1 ≤ n ≤ 100000 1\le n\le 100000 1n100000

思路是归并排序(分治)。先累加左右两边的逆序对数量,然后做二路归并的时候,顺便计算跨越两边的逆序对数量。由于左右两半边已经排好序了,计算跨越两边的逆序对数量变得很简单。当右半边的指针 i i i指向的数 y y y小于左半边指针 j j j指向的数 x x x的时候,就可以累加以 y y y为第二个数的逆序对数列,就是 m − i + 1 m-i+1 mi+1 m m m是左半边的最后一个数的下标。代码如下:

#include <iostream>
using namespace std;
using ll = long long;

const int N = 100010;
int n;
int a[N], tmp[N];

ll merge_sort(int l, int r) {
  if (l >= r) return 0;

  int m = l + (r - l >> 1);
  // 递归求解左右两半边内部的逆序对个数
  ll res = merge_sort(l, m) + merge_sort(m + 1, r);

  // 利用双指针做二路归并,并且将跨中线的逆序对个数累加到res里
  int i = l, j = m + 1, idx = l;
  while (i <= m && j <= r) {
    if (a[i] > a[j]) {
      res += m - i + 1;
      tmp[idx++] = a[j++];
    } else
      tmp[idx++] = a[i++];
  }

  while (i <= m) tmp[idx++] = a[i++];
  while (j <= r) tmp[idx++] = a[j++];

  for (i = l; i <= r; i++) a[i] = tmp[i];
  return res;
}

int main() {
  cin >> n;
  for (int i = 0; i < n; i++) scanf("%d", &a[i]);

  cout << merge_sort(0, n - 1) << endl;
}

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值