给你一个整数数组 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 个更小的元素
示例 2:
输入:nums = [-1]
输出:[0]
示例 3:
输入:nums = [-1,-1]
输出:[0,0]
解题思路
这一题可以用归并排序来计算当前数右侧小于它的元素数量。我们将归并排序做出从大到小排序,当两个从大到小排序好的数组合并时,左数组取一个值放入到额外存储空间时,那么右数组剩余的数量就是比当前数小的数
[*, *, *, *, *] [*, *, *, *]
|
\/
[*]
此时比当前数小的数的个数为右数组的数量
- 首先将当前元素和下标记录到一个数组中
- 然后对这个数组做归并排序
- 当左数组中的值插入到额外数组中时,此时的右数组的数量是比当前值小的值的个数
代码
let temp = []
var mergeSort = function(arr, l, r) {
if (l >= r) return
let mid = (l + r) >> 1
mergeSort(arr, l, mid)
mergeSort(arr, mid + 1, r)
let k = l, p1 = l, p2 = mid + 1
while (p1 <= mid || p2 <= r) {
if ((p2 > r) || (p1 <= mid && arr[p1].val > arr[p2].val)) {
arr[p1].count += r - p2 + 1
temp[k++] = arr[p1++]
} else {
temp[k++] = arr[p2++]
}
}
for (let i = l; i <= r; i++) arr[i] = temp[i]
}
var countSmaller = function(nums) {
let arr = []
for (let i = 0; i < nums.length; i++) arr.push({val: nums[i], index: i, count: 0})
while(temp.length < nums.length) temp.push(0)
mergeSort(arr, 0, arr.length - 1)
let ans = []
for (let i = 0; i < arr.length; i++) ans[arr[i].index] = arr[i].count
return ans
};