题目链接leetcode493. Reverse Pairs
难度等级:hard
思路
这道题很明显是一般逆序对的变形,我们同样可以使用归并排序来解决。
对于已经排序的 a[1 … n] 和 b[1 … m]归并。我们在归并的同时,统计满足题目要求的逆序对的个数,如果存在 a[i] > 2*b[j],就此有j对逆序对(a[i], b[j])、(a[i], b[j - 1])、(a[i], b[j - 2])、、、(a[i], b[0])。那么我们对a数组从i=0到n-1扫描,查找a[i] > 2*b[j]的最大j值,然后就可以计算出所有的逆序对了。这里,统计逆序对的复杂度是O(mn)。那继续观察到一点, i从小到大扫描, 每次找到的满足条件的最大j,后发现,j是递增的, 也就是随着i的增大, 找到的j值是不会减小的,所以,对于在下一轮扫描时候, j不是从0开始遍历,而是从上一轮扫描找到的最大j值开始往后遍历j, 基于此观察, 时间复杂度为O(m + n),至于归并操作,时间复杂度也是O(m+n), 所以归并统计逆序对复杂度是O(m + n), 然后,利用分治策略的归并排序算法, 知道时间复杂度是O(nlogn)
实现
class Solution {
public:
int merge(vector<int> & nums, int l, int m, int r) {
if (l >= r) return 0;
int arr[r - l + 1];
int ll = l, rl = m + 1;
int c = m + 1, index = 0;
int ret = 0;
while(ll < m + 1) {
while(c <= r && nums[ll] > (long long)2*nums[c])
c++;
ret += (c - (m + 1));
while(rl <= r && nums[ll] > nums[rl])
arr[index++] = nums[rl++];
arr[index++] = nums[ll++];
}
while(rl <= r) arr[index++] = nums[rl++];
for(int i = 0; i < (r - l + 1); i++)
nums[l + i] = arr[i];
return ret;
}
int merge_sort(vector<int> & nums, int l, int r) {
if (l >= r) return 0;
int m = l + ((r - l) >> 1);
int ret = 0;
ret += this->merge_sort(nums, l, m) + this->merge_sort(nums, m + 1, r);
ret += this->merge(nums, l, m, r);
return ret;
}
int reversePairs(vector<int>& nums) {
return this->merge_sort(nums, 0, nums.size() - 1);
}
};