题目描述
思路: 利用归并排序的思想当我们希望在数组中求出逆序对的数目时,我们可以使用归并排序的方法。这道题中i < j
且 nums[i] > 2 * nums[j]
的要求与逆序对类似,因此我们也可以使用归并排序的方法求出翻转对的数目。
在归并排序中,当我们归并两个子数组 nums[start .. mid]
和 nums[mid + 1 .. end]
时,我们可以计算出对于前者中的每一个元素nums[i]
,后者中满足 nums[i] > 2 * nums[j]
的j
的数目。由于两个子数组已经排好序,因此对于固定的 i,满足条件的 j
的区间一定是从后者的左端点开始,并且随着 i 的增加,j
区间的右端点不会减小。因此我们可以在 nums[mid + 1 .. end]
中维护一个指针 pos
,表示对于当前的i
,nums[mid + 1 .. pos]
的两倍都小于 nums[i]
。随着 i 的增加,我们尝试向右移动 pos
使得更多的数满足条件。
int reversePairs(vector<int>& nums) {
return mergersort(nums, 0, nums.size()-1);
}
int mergersort(vector<int>& nums, int s, int e)
{
if(s < e)
{
int mid = s + ((e - s) >> 1);
int sum = mergersort(nums, s, mid) + mergersort(nums, mid+1, e);
int j = mid + 1;
for (int i = s; i <= mid; i++) {
while (j <= e && nums[i] > nums[j] * 2LL)
j++;
sum += j - (mid + 1);
}
merger(nums,s,mid,e);
return sum;
}
return 0;
}
int merger(vector<int>& nums, int s, int m, int e)
{
int help[e-s+1];
int r = m + 1;
int l = s;
int res = 0, i = 0;
while(l <= m && r <= e)
{
help[i++] = nums[l] < nums[r] ? nums[l++] : nums[r++];
}
while(l <= m) help[i++] = nums[l++];
while(r <= e) help[i++] = nums[r++];
for(i = s; i <= e; i++)
{
nums[i] = help[i-s];
}
return res;
}
时间复杂度:O(N log N)
。
空间复杂度:O(N)
。