0
点赞
收藏
分享

微信扫一扫

力扣315 计算右侧小于当前元素的个数

非常帅气的昵称吧 2022-05-02 阅读 63

思路:可以看作是查找逆序对的个数。通过归并排序,可以在比较两个数大小的时候知道逆序对的个数,但是如果真的排序,会破坏掉原本数组的顺序,对后续的查找逆序对有影响,因此选择创建一个数组存放下标,每次排序都是对下标排序。

 

 

public List<Integer> countSmaller(int[] nums){
        List<Integer> list=new ArrayList<>();
        int len=nums.length;
        if(len==0){
            return list;
        }
        int[] res=new int[len];
        int[] temp=new int[len];
        int[] indexes=new int[len];
        for(int i=0;i<len;i++){
            indexes[i]=i;
        }
        mergeAndCountSmaller(0,len-1,nums,res,temp,indexes);
        for(int i=0;i<len;i++){
            list.add(res[i]);
        }
        return list;
    }

    private void mergeAndCountSmaller(int left,int right,int[] nums,int[] res,int[] temp,int[] indexes){
        if(left>=right) return;
        int mid=left+(right-left)/2;
        mergeAndCountSmaller(left,mid,nums,res,temp,indexes);
        mergeAndCountSmaller(mid+1,right,nums,res,temp,indexes);
        //优化归并排序
        if(nums[indexes[mid]]<=nums[indexes[mid+1]]){
            return;
        }
        mergeOfTwoSortedArrAndCountSmaller(left,mid,right,nums,res,temp,indexes);
    }

    private void mergeOfTwoSortedArrAndCountSmaller(int left,int mid,int right,int[] nums,int[] res,int[] temp,int[] indexes){
        for(int i=left;i<=right;i++){
            temp[i]=indexes[i];
        }
        int l=left;
        int r=mid+1;
        for(int k=left;k<=right;k++){
            if(l>mid){
                indexes[k]=temp[r++];
            }
            else if(r>right){
                res[temp[l]]+=(right-mid);
                indexes[k]=temp[l++];
            }
            else if(nums[temp[l]]<=nums[temp[r]]){
                res[temp[l]]+=(r-mid-1);
                indexes[k]=temp[l++];
            }
            else {
                indexes[k]=temp[r++];
            }
        }
    }
举报

相关推荐

0 条评论