交易逆序对的总数
题目
LCR 170. 交易逆序对的总数 - 力扣(LeetCode)

逻辑
方法一:双指针逐个比较,会超时
方法二:采用归并排序的思想
- 把数组分成两部分
- 左半部分逆序对的个数为 a,右半部分逆序对的个数为 b,再从左区间/右区间各挑出一个元素,组成 c 个逆序对,此时逆序对的个数为 a+b+c
- 从左区间/右区间各挑出一个元素的时候,保证左右区间有序,如果 numscur1 > numscur2,且数组是降序,那么 cur2,right 区间中的元素都比 numscur1 小,此时逆序对的个数 ret+=right-cur2+1,然后 cur1++
策略1:找出该数之后,有多少个比我小(盯着 cur1 看)
- 如果都是从左侧开始比较
- 找出该数之后,所有比 cur1 小的数之后,cur1才能 ++
- 那么这时候我们需要使用升序数组还是降序数组呢?
假设数组有序排序后是升序
- 如果 numscur1 <= numscur2,说明没有比 cur1 小的了,cur1++
- 如果 numscur1 > numscur2,ret+=cur2-mid+1+1,cur2++,会出现重复计算的问题

假设数组有序排序后是降序
- 如果 numscur1<=numscur2,cur2++
- 如果 numscur1>numscur2,说明 cur2,right 都比 numscur1 小,ret+=right-cur2+1;此时比 numscur1 小的数都找完了,cur1++

总结:
找出该数之后,有多少个比我小,其实就是找右区间中所有比我小的元素中,最大的那个,又因为是从左到右找,所以用降序
策略2:找出该数之前,有多少个比我大(盯着 cur2 看)
- 如果都是从左侧开始比较
- 找出所有比 cur2 大的数之后,cur2 才能++
- 那么这时候我们需要使用升序数组还是降序数组呢?
假设数组有序排序后是升序
- 如果 numscur1 <= numscur2 ,cur1++
- 如果 numscur1 > numscur2 ,说明 cur1,mid 都大于 numscur2,逆序对 ret+=mid-left+1,此时比 cur2 大的数都找到了,cur2++

假设数组有序排序后是降序
- 如果 numscur1 > numscur2,逆序对 ret+=cur1-left+1,cur1++,会有重复计算的问题
- 如果 numscur1<=numscur2,此时比 cur2 大的数都找完了,cur2++

总结:
找出该数之前,有多少个比我大,其实就是找左区间中所有比我大的元素中,最小的那个,又因为是从左到右,所以用升序
代码
cpp
class Solution {
vector<int> tmp;
public:
int reversePairs(vector<int>& nums) {
tmp.reserve(nums.size());
return mergeSort(nums,0,nums.size()-1);
}
int mergeSort(vector<int>& nums,int left,int right)
{
if(left>=right) return 0;
int mid=(left+right)>>1;
// 逆序对的个数=
// 左区间逆序对的个数a+
// 右区间逆序对的个数c+
// 左右区间各自挑出一个元素组成的逆序对个数c
int ret=0;
ret+=mergeSort(nums,left,mid);
ret+=mergeSort(nums,mid+1,right);
// 一边排序,一遍找逆序对
int cur1=left,cur2=mid+1,i=left;
while(cur1<=mid && cur2<=right)
{
// 找出该数之后,有多少个元素比我小,降序
if(nums[cur1]<=nums[cur2]) tmp[i++]=nums[cur2++];
else
{
ret+=right-cur2+1;
tmp[i++]=nums[cur1++];
}
}
while(cur1<=mid) tmp[i++]=nums[cur1++];
while(cur2<=right) tmp[i++]=nums[cur2++];
// 归并
for(int j=left;j<=right;j++) nums[j]=tmp[j];
return ret;
}
};