给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例:
输入: [5,2,6,1]
输出: [2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.
思路:我们先看另一道题:
给你一个数组,对于每个位置i,求出所有在i之前的比位置i上的数大的数
这不就是求逆序数嘛,这道题不是大同小异嘛,我们想一下求逆序数比较快速的方法,树状数组? 归并排序?线段树?
其实都是可以的,我们采用比较常用的归并排序吧。
对于三个数组的解释:
temp:存储元素的初始索引
indexes:存储元素排序后的最终索引
counter:每个位置上的答案
class Solution {
private int[] temp;
private int[] counter;
private int[] indexes;
public List<Integer> countSmaller(int[] nums) {
List<Integer> res=new ArrayList<>();
int len=nums.length;
if(len==0) return res;
temp=new int[len];
counter=new int[len];
indexes=new int[len];
for(int i=0;i<len;i++) indexes[i]=i;
mergeAndCountSmaller(nums,0,len-1);
for(int i=0;i<len;i++)
res.add(counter[i]);
return res;
}
private void mergeAndCountSmaller(int[] nums,int l,int r)
{
if(l==r) return;
int mid=l+(r-l)/2;
mergeAndCountSmaller(nums,l,mid);
mergeAndCountSmaller(nums,mid+1,r);
if(nums[indexes[mid]]>nums[indexes[mid+1]])
mergeOfTwoSortedArrAndCountSmaller(nums,l,mid,r);
}
private void mergeOfTwoSortedArrAndCountSmaller(int[] nums,int l,int mid,int r)
{
for(int i=l;i<=r;i++)
temp[i]=indexes[i];
int i=l,j=mid+1;
for(int k=l;k<=r;k++)
{
if(i>mid)
{
indexes[k]=temp[j];
j++;
}
else if(j>r)
{
indexes[k]=temp[i];
i++;
counter[indexes[k]]+=r-mid;
}
else if(nums[temp[i]]<=nums[temp[j]])
{
indexes[k]=temp[i];
i++;
counter[indexes[k]]+=(j-mid-1);
}
else
{
indexes[k]=temp[j];
j++;
}
}
}
}