[路飞]_leetcode_315.计算右侧小于当前元素的个数

239 阅读1分钟

给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

示例 1:

输入:nums = [5,2,6,1]
输出:[2,1,1,0] 
解释:
5 的右侧有 2 个更小的元素 (21)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素

示例 2:

输入:nums = [-1]
输出:[0]

示例 3:

输入:nums = [-1,-1]
输出:[0,0]

解题思路

这一题可以用归并排序来计算当前数右侧小于它的元素数量。我们将归并排序做出从大到小排序,当两个从大到小排序好的数组合并时,左数组取一个值放入到额外存储空间时,那么右数组剩余的数量就是比当前数小的数

[*, *, *, *, *] [*, *, *, *]
 |
 \/
[*]

此时比当前数小的数的个数为右数组的数量
  1. 首先将当前元素和下标记录到一个数组中
  2. 然后对这个数组做归并排序
  3. 当左数组中的值插入到额外数组中时,此时的右数组的数量是比当前值小的值的个数

代码

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
};