[关闭]
@ysner 2021-10-21T21:55:27.000000Z 字数 2320 阅读 900

LeetCode315—计算右侧小于当前元素的个数

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


第一次提交的代码:(归并排序+索引数组)

  1. class Solution
  2. {
  3. public int[] count,index,t;
  4. public int n;
  5. public List<Integer> countSmaller(int[] nums)
  6. {
  7. List<Integer> ans=new ArrayList<>();
  8. n=nums.length;
  9. count=new int[n];
  10. index=new int[n];
  11. t=new int[n];
  12. for(int i=0;i<n;i++) index[i]=i;
  13. Merge(nums,0,n-1);
  14. for(int i=0;i<n;i++)
  15. ans.add(count[i]);
  16. //主要是因为ArrayList里修改元素不太方便,所以统计逆序对数时不用ans而新开一个count
  17. return ans;
  18. }
  19. public void Merge(int[] nums,int L,int R)//实现归并排序的函数,应用分治思想
  20. {
  21. if(L==R) return;//分治终止条件
  22. int mid=(L+R)/2;
  23. Merge(nums,L,mid);Merge(nums,mid+1,R);
  24. if(nums[index[mid]]>nums[index[mid+1]]) Sort(nums,L,mid,R);
  25. //如果两子数组合并后无序,则进行合并排序
  26. }
  27. public void Sort(int[] nums,int L,int mid,int R)//将两个有序数组合并成一个有序数组
  28. {
  29. for(int i=L;i<=R;i++) t[i]=index[i];//一开始写的范围是0到n-1,然后直接超时QAQ
  30. int i=L,j=mid+1;
  31. for(int k=L;k<=R;k++)
  32. {
  33. if(i>mid) index[k]=t[j++];
  34. else if(j>R)
  35. {
  36. index[k]=t[i++];
  37. count[index[k]]+=(R-mid);//加左边的元素时,右边比其先加的元素都构成逆序对
  38. }
  39. else if(nums[t[i]]<=nums[t[j]])
  40. {
  41. index[k]=t[i++];
  42. count[index[k]]+=(j-mid-1);//加左边的元素时,右边比其先加的元素都构成逆序对
  43. }
  44. else index[k]=t[j++];
  45. }
  46. }
  47. }

第二次提交的代码:(树状数组)

  1. class Solution
  2. {
  3. public int[] tree=new int[20002];
  4. //t是树状数组,树状数组的第i位储存着值为i-10001的数的个数。树状数组维护的是前缀和
  5. public List<Integer> countSmaller(int[] nums)
  6. {
  7. List<Integer> ans=new ArrayList<>();
  8. int n=nums.length;
  9. for(int i=n-1;i>=0;i--)
  10. {
  11. int t=nums[i]+10001;//将数组元素中的负数转化为正数,方便用树状数组维护
  12. Add(t);
  13. ans.add(Query(t-1));
  14. }
  15. Collections.reverse(ans);//将数组或列表反转的内置函数
  16. return ans;
  17. }
  18. public void Add(int x)//树状数组模板
  19. {
  20. for(;x<=20001;x+=x&-x) tree[x]++;
  21. }
  22. public int Query(int x)//树状数组模板
  23. {
  24. int tot=0;
  25. for(;x>0;x-=x&-x) tot+=tree[x];//树状数组的0号位不能用,否则死循环!!!
  26. return tot;
  27. }
  28. }

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

  1. class Solution
  2. {
  3. public int[] tree,a;
  4. public int n,size;
  5. public List<Integer> countSmaller(int[] nums)
  6. {
  7. List<Integer> ans=new ArrayList<>();
  8. n=nums.length;
  9. Discentralize(nums);
  10. for(int i=n-1;i>=0;i--)
  11. {
  12. int id=getId(nums[i]);
  13. Add(id);
  14. ans.add(Query(id-1));
  15. }
  16. Collections.reverse(ans);
  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<Integer> set=new HashSet<Integer>();//利用HashSet的元素不同的特性来去重
  32. for (int num:nums) set.add(num);//for (int num:nums)遍历整个nums容器的方法
  33. size=set.size();
  34. a=new int[size];
  35. tree=new int[size+5];
  36. int index=0;
  37. for (int num:set) a[index++] = num;
  38. Arrays.sort(a);
  39. }
  40. public int getId(int w)//二分查找确定每个数的编号
  41. {
  42. int L=0,R=size-1;
  43. while(L<R)
  44. {
  45. int mid=L+R>>1;
  46. if(a[mid]>=w) R=mid;
  47. else L=mid+1;
  48. }
  49. return R+1;
  50. }
  51. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注