题目详情
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
——题目难度:困难
思路
上图来源:力扣官方
归并排序(采用分治策略)
当使用归并排序的时候,"合并"的这一过程跟逆序对的计算有关。因为每次"合并"的时候,前半部分子序列跟后半部分子序列比较的过程会和逆序对的个数有关系:
将nums[j](后半部分子序列)看成比较的对象的话
然后当nums[i]>nums[j]的时候,包括nums[i]在内的 前半数组剩余的数字(也就是下标到mid为止的剩余数字) 都要比nums[j]大---因为前半数组排好序了,所以针对nums[j]来说 此刻新增的逆序对数目就是(mid-i+1)
-下面代码
class Solution {
public:
int count = 0;
int reversePairs(vector<int>& nums) {
if(nums.size()==0) return 0;
vector<int> replica(nums.size(),0);
Merge_Sort(0,nums.size()-1,replica,nums);
return count;
}
//l表示left, r表示right
void Merge_Sort(int l,int r,vector<int> &replica, vector<int> &nums){
if(l==r) return ; //分成一个元素就无需再分了
int mid = (l+r)/2;
Merge_Sort(l,mid,replica,nums); //"分"的部分
Merge_Sort(mid+1,r,replica,nums); //"分"的部分
int i=l,j=mid+1,pos=l; //"治"的部分
while(i<=mid && j<=r) {
if(nums[i]>nums[j]){
replica[pos++]=nums[j++];
count += (mid-i+1); // 将nums[j]看成比较的对象, 针对nums[j]来说 此刻新增的逆序对数目就是(mid-i+1)
}else{
replica[pos++]=nums[i++];
}
}
if(i<=mid) copy(nums.begin()+i, nums.begin()+mid+1, replica.begin()+pos);
else if(j<=r) copy(nums.begin()+j, nums.begin()+r+1, replica.begin()+pos);
copy(replica.begin()+l, replica.begin()+r+1, nums.begin()+l); //将已经排好序的replica拷贝到nums中去
}
};
结果