Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].
You need to return the number of important reverse pairs in the given array.
Example1:
Input: [1,3,2,3,1]
Output: 2
Example2:
Input: [2,4,3,5,1]
Output: 3
Note:
The length of the given array will not exceed 50,000.
All the numbers in the input array are in the range of 32-bit integer.
在学习王争的数据结构与算法之美看到老师讲分治法,首先是分治法应用于归并排序,然后解决这道题。分治法是一种解决问题的思想,分解问题,解决子问题,合并答案。
这道题实说要找出数组中有多少个逆序对,暴力法复杂度
O
(
n
2
)
O(n^{2})
O(n2),这道题可以巧妙地用归并排序解决。
为了求的整个数组的逆序数,我们可以分别求各一半数组的逆序对数,假设分别为a个和b个,再求两个子数组之间的逆序数,假设为c,最终的逆序数即为a+b+c.
我们在合并函数中可以同时计算出两个子数组间的逆序数,该结果就作为上一层子数组的逆序数,自下而上递归回去就能算出整个数组的逆序数了。
注:这儿我们需要用long long来存数组的值,因为有个2*nums[i]操作,若用int会造成数值溢出。总的来说就是在归并排序代码基础上加了个求逆序数的操作。
class Solution {
public:
int reversePairs(vector<int>& nums) {
int res=0;
vector<long long> nums_long(nums.begin(),nums.end());
mergeSortHelper(nums_long,0,nums.size()-1,res);
//for (int a:nums) cout<<a<<" ";
return res;
}
void mergeSortHelper(vector<long long>& nums,int low,int high,int& numbers)
{
if (low>=high) return;
int mid=(low+high)/2;
mergeSortHelper(nums,low,mid,numbers);
mergeSortHelper(nums,mid+1,high,numbers);
merge(nums,low,mid,high,numbers);
}
void merge(vector<long long>& nums,int low,int mid,int high,int& numbers)
{
int i=low,j=mid+1,k=0;
vector<long long> tmp(high-low+1);
// 子数组内的数据已经是有序的了,故找到nums[i]>2*nums[j],那么i后面的所有数据都大于2*nums[j]
while(i<=mid&&j<=high)
{
if(nums[i]<=2*nums[j]) i++;
else
{
numbers += mid-i+1;
j++;
}
}
// 这段代码是将两个有序子数组合并成一个有序的数组
i=low,j=mid+1;
while(i<=mid&&j<=high)
{
//cout<<nums[i]<<" "<<nums[j]<<endl;
if(nums[i]<nums[j]) tmp[k++]=nums[i++];
else
{
tmp[k++]=nums[j++];
}
}
if(i>mid)
{
while(j<=high) tmp[k++]=nums[j++];
}
else
{
while(i<=mid) tmp[k++]=nums[i++];
}
for (i=0;i<high-low+1;i++)
{
nums[low+i]=tmp[i];
}
}
};