题解 | #数组中的逆序对# 归并排序 : 递归, 二分
数组中的逆序对
https://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0ec6c5
class Solution { private: const int kmod = 1000000007; public: void merge_sort__(vector<int>& arr, vector<int>& tmp, int l, int r, int& ret) { if(l>=r) { return; } int mid = (r+l)/2; // 二分后 再分别 divide merge_sort__(arr, tmp, l, mid, ret); merge_sort__(arr, tmp, mid+1, r, ret); // 分完之后的 治 最底层是 前后半个区间里的 首两个元素的合并 merge__(arr, tmp, l, r, mid, ret); } void merge__(vector<int>& arr, vector<int>& tmp, int l, int r, int mid, int& ret) { // ret 保存 逆序对数 取余的答案 // 刚才提到在函数内部开辟额外空间的做法很不好。因为这样会涉及到频繁的构建 vector 和析构vector,所以比较好的做法是:直接在最外层开辟一个足够大的数组,然后传引用到函数。 // vector<int> tmp(r-l+1); // 两部分的总长度 int i = l, j = mid+1, k=0; // i 和 j各自从 首元素开始 while(i<=mid && j<=r) { // 比较大小 if(arr[i]<arr[j]) { tmp[k++] = arr[i++]; } else { // i<j 但元素值相反 是逆序 tmp[k++] = arr[j++]; // ret++; // miao 由于 [l, mid] [mid+1, r] 已经是各自有序的 所以当a[i]>a[j] // 那么从i 道mid 这 mid-i+1 计几个元素和j 都可构成逆序对 ret += (mid-i+1); ret %= kmod; } } // 剩余的元素全放在tmp后面 这是指两半 元素不等的情况 while(i<=mid) { tmp[k++] = arr[i++]; } while(j<=r) { tmp[k++] = arr[j++]; } //再赋值给 arr本身 才能保证每次归并 两部份都是有序 for(int i=l, k=0; i<=r; ++i, ++k) { arr[i] = tmp[k]; // 注意这里 赋值回去时还在 arr[l,r] 内 但tmp 每次只是用了前(r-l+1)的地方 } } // 暴力枚举 会超时 // 官解二: 归并排序的思想 int InversePairs(vector<int> data) { int n = data.size(); vector<int> tmp(n); //直接在这里开个中间变量 否则放在内部 还会超时 int cnt = 0; merge_sort__(data, tmp, 0, n-1, cnt); return cnt; } };