1,题目:
此题暴力写的话很简单,但是这是困难题,暴力时间复杂度坑定是过不去的,不可以哦。
2,归并新用法。
归并排序不讲哦:讲新奇的用法
看图:在归的过程中不断算出红色方框的逆序对,不断的从下往上算逆序对,并不断累加就ok了。
为什么是对的呢,因为是对应位置的,不会重复的逆序对被统计。其次最终要的是归并排序在归并的时候是有序的,俩个有序的归成一个有序的,我们要求出那俩个有序的组成的逆序对,就非常简单了。效率也就非常高了,利用了有序的性质,非常的巧妙。。
3.代码实现
关键部位都有注释,如果还有问题的话,可以一步leetcode 官方解释。
class Solution {
public:
int mergeSort(vector<int>& nums, vector<int>& tmp, int l, int r) {
if (l >= r) {
return 0;
}
int mid = (l + r) / 2;
int inv_count = mergeSort(nums, tmp, l, mid) + mergeSort(nums, tmp, mid + 1, r);
int i = l, j = mid + 1, pos = l;
//第一种情况。 都没完
while (i <= mid && j <= r) {
if (nums[i] <= nums[j])
{
tmp[pos] = nums[i];
++i; //左开右闭 正好是我们需要的个数。
inv_count += (j - (mid + 1));
}
else
{
tmp[pos] = nums[j];
++j;
}
++pos;
}
//第二中情况处理。 后面先完了。
for (int k = i; k <= mid; ++k) {
tmp[pos++] = nums[k];
inv_count += (j - (mid + 1));
}
//第三种情况 前面先完了。
for (int k = j; k <= r; ++k) {
tmp[pos++] = nums[k];
}
//把归并好的有序元素拷贝回原来的位置。 为什么不在原来数组上归并呢???因为会有数据覆盖,不可以在原来数组归并。。
//把前面的拷贝到后面中去。 左闭 右开
//加的是l 不是 1
copy(tmp.begin() + l, tmp.begin() + r + 1, nums.begin() + l);
//返回当前归并的个数。
return inv_count;
}
int reversePairs(vector<int>& nums) {
int n = nums.size();
vector<int> tmp(n);
return mergeSort(nums, tmp, 0, n - 1);
}
};