[关闭]
@ysner 2021-10-26T06:21:02.000000Z 字数 1733 阅读 704

LeetCode493—翻转对

排序 树状数组 离散化 二分查找


第一次提交的代码:(树状数组+离散化+二分查找)

  1. class Solution
  2. {
  3. public int[] tree;
  4. public long[] a;
  5. public int n,size;
  6. public int reversePairs(int[] nums)
  7. {
  8. int ans=0;
  9. n=nums.length;
  10. Discentralize(nums);
  11. for(int i=n-1;i>=0;i--)
  12. {
  13. int id=getId(nums[i]),id2=getId((long)nums[i]*2);//小心乘法爆int!设long即可
  14. ans+=Query(id-1);//先查询答案再添加!否则自己就有可能和自己成逆序对了QAQ
  15. Add(id2);//因为查询的都是num*2,所以添加的也是num*2
  16. }
  17. return ans;
  18. }
  19. public void Add(int x)//树状数组模板
  20. {
  21. for(;x<=size;x+=x&-x) tree[x]++;
  22. }
  23. public int Query(int x)//树状数组模板
  24. {
  25. int tot=0;
  26. for(;x>0;x-=x&-x) tot+=tree[x];
  27. return tot;
  28. }
  29. public void Discentralize(int[] nums) //将数组离散化:去重+编号(分配的编号就是位置标号+1)
  30. {
  31. Set<Long> set=new HashSet<>();//利用HashSet的元素不同的特性来去重
  32. for (long num:nums)
  33. {
  34. set.add(num);
  35. set.add(num*2);//因为树状数组要维护num*2,所以也要将其离散化,给其一个标号
  36. }
  37. size=set.size();
  38. a=new long[size];
  39. tree=new int[size+5];
  40. int index=0;
  41. for (long num:set) a[index++] = num;//for(long num:set)能实现对整个容器/数组的遍历
  42. Arrays.sort(a);
  43. }
  44. public int getId(long w)//二分查找确定每个数的编号
  45. {
  46. int L=0,R=size-1;
  47. while(L<R)
  48. {
  49. int mid=L+R>>1;
  50. if(a[mid]>=w) R=mid;
  51. else L=mid+1;
  52. }
  53. return R+1;
  54. }
  55. }

第二次提交的代码:(归并排序)

  1. class Solution
  2. {
  3. public int n,ans=0;
  4. public int reversePairs(int[] nums)
  5. {
  6. n=nums.length;
  7. Merge(nums,0,n-1);
  8. return ans;
  9. }
  10. public void Merge(int[] nums,int L,int R)//实现归并排序的函数,应用分治思想
  11. {
  12. if(L==R) return;//分治终止条件
  13. int mid=(L+R)/2;
  14. Merge(nums,L,mid);Merge(nums,mid+1,R);
  15. int i=L,j=mid+1;
  16. for(;i<=mid;i++)
  17. {
  18. while(j<=R&&nums[i]>(long)nums[j]*2) j++;//不要在j++后面搞j--,不如直接在统计时-1
  19. ans+=(j-mid-1);
  20. }
  21. //统计答案过程不能放Sort里,因为有些有序数组也存在翻转对
  22. if(nums[mid]>nums[mid+1]) Sort(nums,L,mid,R); //如果两子数组合并后无序,则进行合并排序
  23. }
  24. public void Sort(int[] nums,int L,int mid,int R)//将两个有序数组合并成一个有序数组
  25. {
  26. int[] t=new int[R-L+1];//开n大小的数组会超级慢QAQ
  27. int i=L,j=mid+1;
  28. for(int k=L;k<=R;k++)
  29. if(i>mid) t[k-L]=nums[j++];
  30. else if(j>R) t[k-L]=nums[i++];
  31. else if(nums[i]<=nums[j]) t[k-L]=nums[i++];
  32. else t[k-L]=nums[j++];
  33. for(int k=L;k<=R;k++) nums[k]=t[k-L];//将旧数组替换为已排好序的数组
  34. }
  35. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注