題目描述
思路: 利用歸併排序的思想當我們希望在數組中求出逆序對的數目時,我們可以使用歸併排序的方法。這道題中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)
。