给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。
示例 1:
输入: [1,3,2,3,1]
输出: 2
示例 2:
输入: [2,4,3,5,1]
输出: 3
思路:归并排序
首先,在 merge
函数中做点手脚,当 nums[lo..mid]
和 nums[mid+1..hi]
两个子数组完成排序后,对于 nums[lo..mid]
中的每个元素 nums[i]
,去 nums[mid+1..hi]
中寻找符合条件的 nums[j]
就行了。
此外,因为子数组 nums[lo..mid]
是排好序的,也就是 nums[i] <= nums[i+1]
。
所以,对于 nums[i],low<=i<=mid
,在找到的符合 nums[i]>2*nums[j]
的nums[j], mid+1<=j <=hi
,也必然也符合 nums[i+1]>2*nums[j]
。
因此,我们不需要每次都去遍历整个nums[mid+1..hi]
,只要维护一个边界 end
,count+=end-(mid+1),当找到nums[i]对应的end后,nums[i+1]只需要判断end边界是否需要再向右扩即可,此时count+=end-(mid+1)。
class Solution {
public:
int count=0;
vector<int> tmp;
int reversePairs(vector<int>& nums)
{
tmp.resize(nums.size());
sort(nums,0,nums.size()-1);
return count;
}
void sort(vector<int>& nums,int low,int high)
{
if(low>=high)
return ;
int mid=(low+high)/2;
sort(nums,low,mid);
sort(nums,mid+1,high);
merge(nums,low,mid,high);
}
void merge(vector<int>& nums,int low,int mid,int high)
{
for(int i=low;i<=high;i++) {
tmp[i]=nums[i];
}
int end=mid+1;
for(int i=low;i<=mid;i++)
{
while(end<=high&&(long)nums[i]>(long)nums[end]*2)
{
end++;
}
count+=end-(mid + 1);
}
int i=low;
int j=mid+1;
for(int p=low;p<=high;p++) {
if(i==mid+1) {
nums[p]=tmp[j];
j++;
}
else if(j==high+1)
{
nums[p]=tmp[i];
i++;
}
else if(tmp[i]<tmp[j])
{
nums[p]=tmp[i];
i++;
}
else
{
nums[p]=tmp[j];
j++;
}
}
}
};