Hard
You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].
Example:
Input: [5,2,6,1]
Output: [2,1,1,0]
Explanation:
To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1 smaller element (1).
To the right of 6 there is 1 smaller element (1).
To the right of 1 there is 0 smaller element.
给定一个数组,求数组的每个元素之后比该元素小的元素的个数组成的数组
求逆序相关的问题,归并排序是标准思路。在mergeSort的merge方法中统计先于左半部分数组元素放入新数组的右半部分元素个数加到对应位置的结果中。另外,在mergeSort的过程中维护两个数组ans和ind,分别记录“原数组中每个元素之后比该元素小的元素的个数”和“mergeSort之后当前数组元素在原数组的位置”.
时间复杂度O(nlogn),空间复杂度O(n).
class Solution {
private void mergeSort(int[] nums, int left, int right, int[] ind, Integer[] ans) {
if (left == right) {
return;
}
int mid = (left + right) / 2;
mergeSort(nums, left, mid, ind, ans);
mergeSort(nums, mid+1, right, ind, ans);
merge(nums, left, mid, right, ind, ans);
}
private void merge(int[] nums, int left, int mid, int right, int[] ind, Integer[] ans) {
int[] larr = Arrays.copyOfRange(nums, left, mid+1), rarr = Arrays.copyOfRange(nums, mid+1, right+1), preind = Arrays.copyOfRange(ind, left, right+1);
int i = 0, j = 0, k = left, cnt = 0, nl = larr.length, nr = rarr.length;
while (i < nl && j < nr) {
while (i < nl && j < nr && larr[i] <= rarr[j]) {
ans[preind[i]] += cnt;
ind[k] = preind[i];
nums[k++] = larr[i++];
}
while (i < nl && j < nr && rarr[j] < larr[i]) {
ind[k] = preind[j + nl];
nums[k++] = rarr[j++];
++cnt;
}
}
while (i < nl) {
ans[preind[i]] += cnt;
ind[k] = preind[i];
nums[k++] = larr[i++];
}
while (j < nr) {
ind[k] = preind[j + nl];
nums[k++] = rarr[j++];
}
}
public List<Integer> countSmaller(int[] nums) {
int n = nums.length;
if (n == 0) {
return Collections.emptyList();
}
Integer[] ans = new Integer[n];
Arrays.fill(ans, 0);
int[] ind = new int[n];
for (int i=0; i<n; ++i) {
ind[i] = i;
}
mergeSort(nums, 0, n-1, ind, ans);
return new ArrayList<Integer>(Arrays.asList(ans));
}
}