文章目录
0. 前言
经典问题。这个貌似在LeetCode 剑指 Offer 51. 数组中的逆序对是一道困难问题。
1. 归并应用+逆序对
逆序对这个求解,冒泡可以、归并可以、树状数组也可以。在这就总结一个归并版本。
本质: 归并应用
思路:
- 完全基于归并排序
- 先分治,二路归并数组单调不减
- 在二路归并过程中若出现
q[i]>q[j]
,因为i~mid
各个元素是不减的,所以q[i+1 ~ mid]
就严格大于q[j]
,均与q[j]
构成逆序对。 故在输出q[j]
到备份数组的时候,顺便统计与q[j]
构成逆序对的个数,即答案加上mid - i + 1
。 - 答案会爆
int
模板代码:
#include <iostream>
using namespace std;
const int N = 1e5+5;
int n;
int q[N], tmp[N];
long long merge(int l, int r) {
if (l >= r) return 0;
int mid = l + r >> 1;
long long res = merge(l, mid) + merge(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 res += mid - i + 1, tmp[k++] = q[j++];
}
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() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> q[i];
cout << merge(0, n - 1) << endl;
return 0;
}