分治-归并-493.翻转对-力扣(LeetCode)

[复制链接]
发表于 2025-9-8 22:50:10 | 显示全部楼层 |阅读模式
一、题目解析


1、i<j且nums>2*nums[j],(i,j)记作一个翻转对

2、nums长度不会超过50000

3、nums中所有元素都在32位整数范围内

二、算法原理

解法1:暴力枚举 O(N^2)

固定一个数,枚举另一个数

解法2:分治 O(N*logN)

盘算翻转对 (利用单调性,利用同向双指针)

方法1:盘算当前元素后面,有多少元素的两倍比我小(降序)


由于降序,nums[cur1]>nums[cur2]*2,即nums[cur1]比cur2后面的所有数大,所以cur2~right的个数为right-cur2+1

方法2:盘算当前元素之前,有多少元素的一样平常比我大(升序)


除2.0为了制止去不尽的情况,由于升序,nums[cur1]/2.0>nums[cur2],nums[cur2]比cur1后面的所有数小,所以cur1~mid的个数为mid-cur1+1

归并两个有序数组


在升序中,tmp[i++] = nums[cur1]<=nums[cur2] ? nums[cur1++] : nums[cur2++]

在降序中,tmp[i++] = nums[cur1]<=nums[cur2] ? nums[cur2++] : nums[cur1++]

三、代码示例

解法2:降序
  1. int tmp[50005];
  2. public:
  3.     //降序
  4.     int reversePairs(vector<int>& nums)
  5.     {
  6.         return mergeSort(nums,0,nums.size()-1);
  7.     }
  8.     int mergeSort(vector<int>& nums,int left,int right)
  9.     {
  10.         int ret = 0;
  11.         if(left>=right) return 0;
  12.         int mid = (left+right)>>1;
  13.         ret += mergeSort(nums,left,mid);
  14.         ret += mergeSort(nums,mid+1,right);
  15.         //统计翻转对
  16.         int cur1 = left,cur2 = mid+1;
  17.         while(cur1<=mid)
  18.         {
  19.             while(cur2<=right && nums[cur1]/2.0 <= nums[cur2]) cur2++;
  20.             if(cur2>right) break;
  21.             ret += right-cur2+1;
  22.             cur1++;
  23.         }
  24.         int curr1 = left,curr2 = mid+1,i = 0;
  25.         while(curr1<=mid && curr2<=right)
  26.             tmp[i++] = nums[curr1]<=nums[curr2] ? nums[curr2++] : nums[curr1++];
  27.         //处理未遍历完
  28.         while(curr1<=mid) tmp[i++] = nums[curr1++];
  29.         while(curr2<=right) tmp[i++] = nums[curr2++];
  30.         //还原
  31.         for(int i = left;i<=right;i++)
  32.             nums[i] = tmp[i-left];
  33.         return ret;
  34.     }
复制代码
这里不是nums[cur2]*2缘故起因是,固然都是32位整数范围内,但是*2可能会导致积超过32位的范围,所以/2.0


解法2:升序
  1. int tmp[50005];
  2. public:
  3. //升序
  4.     int reversePairs(vector<int>& nums)
  5.     {
  6.         return mergeSort(nums,0,nums.size()-1);
  7.     }
  8.     int mergeSort(vector<int>& nums,int left,int right)
  9.     {
  10.         int ret = 0;
  11.         if(left>=right) return 0;
  12.         int mid = (left+right)>>1;
  13.         ret += mergeSort(nums,left,mid);
  14.         ret += mergeSort(nums,mid+1,right);
  15.         //统计翻转对
  16.         int cur1 = left,cur2 = mid+1;
  17.         while(cur2<=right)
  18.         {
  19.             while(cur1<=mid && nums[cur1]/2.0 <= nums[cur2]) cur1++;
  20.             if(cur1>mid) break;
  21.             ret += mid-cur1+1;
  22.             cur2++;
  23.         }
  24.         int curr1 = left,curr2 = mid+1,i = 0;
  25.         while(curr1<=mid && curr2<=right)
  26.             tmp[i++] = nums[curr1]<=nums[curr2] ? nums[curr1++] : nums[curr2++];
  27.         //处理未遍历完
  28.         while(curr1<=mid) tmp[i++] = nums[curr1++];
  29.         while(curr2<=right) tmp[i++] = nums[curr2++];
  30.         //还原
  31.         for(int i = left;i<=right;i++)
  32.             nums[i] = tmp[i-left];
  33.         return ret;
  34.     }
复制代码


看到末了,如果对您有所帮助,还请点赞、收藏和关注,我们下期再见!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表