题目
给你一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例 1:
输入:nums = [5,2,6,1]
输出:[2,1,1,0]
解释:5 的右侧有 2 个更小的元素 (2 和 1)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素
题解
利用归并排序的过程进行统计,这样有两个好处可以提升统计的效率:
1、归并的时候右边的数组元素一定是在左边组数组元素的右边
2、由于是有序数组可以进行快速的统计,提升统计的效率
java
class Solution {
//用于记录原本数组对应的位置和数值
private class Pair{
int val, id;
public Pair(int val,int id){
this.val=val;
this.id=id;
}
}
private Pair[] temp;
private int[] count;
public List<Integer> countSmaller(int[] nums) {
int n=nums.length;
count=new int[n];
temp=new Pair[n];
Pair[] arr=new Pair[n];
for(int i=0;i<n;i++){
arr[i]=new Pair(nums[i],i);
}
sort(arr,0,n-1);
List<Integer> res=new LinkedList<>();
for(int c:count) res.add(c);
return res;
}
private void sort(Pair[] arr,int left,int right){
if(left==right) return;
int mid=left+(right-left)/2;
sort(arr,left,mid);
sort(arr,mid+1,right);
merge(arr,left,mid,right);
}
private void merge(Pair[] arr,int left,int mid,int right){
for(int i=left;i<=right;i++){
temp[i]=arr[i];
}
int l=left,m=mid+1;
for(int i=left;i<=right;i++){
//左边已经排好
if(l==mid+1){
arr[i]=temp[m];
m++;
}else if(m==right+1){//右边已经排好
arr[i]=temp[l];
l++;
//更新count数组,右侧的所有元素都比当前元素小
count[arr[i].id]+=m-mid-1;
//左边比右边大
}else if(temp[l].val>temp[m].val){//右侧元素比左侧元素小
arr[i]=temp[m];
m++;
}else{
//左边比右边小
arr[i]=temp[l];
l++;
//右边的当前元素之前的所有元素都比左边数组的当前元素小
count[arr[i].id]+=m-mid-1;
}
}
}
}