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

252 阅读2分钟

315. 计算右侧小于当前元素的个数

题目

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

示例

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

题解

循环+二分

比如数组nums = [5,2,6,1];临时数组list;结果数据result = [];

从右到左枚举第1个位置1,list此时为空,将1放入list = [1]; result.unshift(0)

第2个位置6,将6通过二分法插入list数组,得到list = [6,1],6左边有1位数,result.unshift(1);

第3个位置2,将2通过二分法插入list数组,得到list = [6,2,1],2左边有1位数,result.unshift(1);

第4个位置5,将5通过二分法插入list数组,得到list = [6,5,2,1],5左边有2位数,result.unshift(2);

结果返回resutl = [2,1,1,0]

代码

var countSmaller = function (nums) {
  const len = nums.length
  let list = []
  let result = Array(len)
  for (let i = len - 1; i >= 0; i--) {
    let l = 0
    let r = list.length
    while (l < r) {
      const mid = l + Math.floor((r - l) / 2)
      if (list[mid] >= nums[i]) {
        r = mid
      } else {
        l = mid + 1
      }
    }
    result[i] = l
    list.splice(l, 0, nums[i])
  }

  return result
}

归并

  • 利用归并排序思想
  • 归并过程将数组分为有序的left和right
  • 在合并left和right过程中,对于任意left中元素,right的索引x即为原数组中当前元素左侧有n+x个小于当前元素的值;其中n是上一次【并】过来的数量
  • 归并过程中如何知道当前元素中在原数组的下标?
  • 利用数组对象,将nums数组重新组合变成{num:'值',index,'下标'}

根据上述思路编辑代码如下

var countSmaller = function (nums) {
  const len = nums.length
  let result = Array(len).fill(0)
  const list = nums.map((v, i) => ({ num: v, index: i }))
  mergeSort(list)

  return result
  function mergeSort(nums) {
    //获取数组长度
    const len = nums.length

    //如果数组长度小于2返回数组
    if (len < 2) return nums

    // 否则分割数组
    const mid = len >> 1 //右移1位,类似除以2

    // 递归分解左侧数组
    const left = mergeSort(nums.slice(0, mid))

    // 递归分解右侧数组
    const right = mergeSort(nums.slice(mid, len))

    // 合并左右两个数组
    return merge(left, right)

    // 合并数组
  }
  function merge(left, right) {
    let l = 0
    let r = 0
    let list = []
    while (l < left.length && r < right.length) {
      //console.log('left', left)
      if (left[l].num <= right[r].num) {
        list.push(left[l])

        result[left[l].index] += r
        l++
      } else {
        list.push(right[r])

        r++
      }
    }
    if (l === left.length) {
      list = list.concat(right.slice(r, right.length))
    }
    if (r === right.length) {
      while (l < left.length) {
        list.push(left[l])
        result[left[l].index] += r
        l++
      }
    }

    return list
  }
}