@ysner
2021-10-21T13:55:27.000000Z
字数 2320
阅读 1410
排序 离散化 树状数组 二分查找
第一次提交的代码:(归并排序+索引数组)
class Solution{public int[] count,index,t;public int n;public List<Integer> countSmaller(int[] nums){List<Integer> ans=new ArrayList<>();n=nums.length;count=new int[n];index=new int[n];t=new int[n];for(int i=0;i<n;i++) index[i]=i;Merge(nums,0,n-1);for(int i=0;i<n;i++)ans.add(count[i]);//主要是因为ArrayList里修改元素不太方便,所以统计逆序对数时不用ans而新开一个countreturn ans;}public void Merge(int[] nums,int L,int R)//实现归并排序的函数,应用分治思想{if(L==R) return;//分治终止条件int mid=(L+R)/2;Merge(nums,L,mid);Merge(nums,mid+1,R);if(nums[index[mid]]>nums[index[mid+1]]) Sort(nums,L,mid,R);//如果两子数组合并后无序,则进行合并排序}public void Sort(int[] nums,int L,int mid,int R)//将两个有序数组合并成一个有序数组{for(int i=L;i<=R;i++) t[i]=index[i];//一开始写的范围是0到n-1,然后直接超时QAQint i=L,j=mid+1;for(int k=L;k<=R;k++){if(i>mid) index[k]=t[j++];else if(j>R){index[k]=t[i++];count[index[k]]+=(R-mid);//加左边的元素时,右边比其先加的元素都构成逆序对}else if(nums[t[i]]<=nums[t[j]]){index[k]=t[i++];count[index[k]]+=(j-mid-1);//加左边的元素时,右边比其先加的元素都构成逆序对}else index[k]=t[j++];}}}
第二次提交的代码:(树状数组)
class Solution{public int[] tree=new int[20002];//t是树状数组,树状数组的第i位储存着值为i-10001的数的个数。树状数组维护的是前缀和public List<Integer> countSmaller(int[] nums){List<Integer> ans=new ArrayList<>();int n=nums.length;for(int i=n-1;i>=0;i--){int t=nums[i]+10001;//将数组元素中的负数转化为正数,方便用树状数组维护Add(t);ans.add(Query(t-1));}Collections.reverse(ans);//将数组或列表反转的内置函数return ans;}public void Add(int x)//树状数组模板{for(;x<=20001;x+=x&-x) tree[x]++;}public int Query(int x)//树状数组模板{int tot=0;for(;x>0;x-=x&-x) tot+=tree[x];//树状数组的0号位不能用,否则死循环!!!return tot;}}
第三次提交的代码:(树状数组+离散化+二分查找)
class Solution{public int[] tree,a;public int n,size;public List<Integer> countSmaller(int[] nums){List<Integer> ans=new ArrayList<>();n=nums.length;Discentralize(nums);for(int i=n-1;i>=0;i--){int id=getId(nums[i]);Add(id);ans.add(Query(id-1));}Collections.reverse(ans);return ans;}public void Add(int x){for(;x<=size;x+=x&-x) tree[x]++;}public int Query(int x){int tot=0;for(;x>0;x-=x&-x) tot+=tree[x];return tot;}public void Discentralize(int[] nums) //将数组离散化:去重+编号(分配的编号就是位置标号+1){Set<Integer> set=new HashSet<Integer>();//利用HashSet的元素不同的特性来去重for (int num:nums) set.add(num);//for (int num:nums)遍历整个nums容器的方法size=set.size();a=new int[size];tree=new int[size+5];int index=0;for (int num:set) a[index++] = num;Arrays.sort(a);}public int getId(int w)//二分查找确定每个数的编号{int L=0,R=size-1;while(L<R){int mid=L+R>>1;if(a[mid]>=w) R=mid;else L=mid+1;}return R+1;}}
