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

简介: leetcode-315-计算右侧小于当前元素的个数


网络异常,图片无法展示
|


[题目地址][B站地址]


给你一个整数数组 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]
复制代码


提示:


  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104


解题思路


本题首先可以想到的最简单直接的解题方式是双层循环,内层循环遍历外层循环当前元素后面的元素,如果小于当前元素,则当前元素结果值 +1。这样内层循环结束,就得到了外层循环当前元素的右侧小于它的元素的个数。


但是这样的解题方式时间复杂度是 O(n²) 的,无法达到本题的要求。


那如何才能更高效的求得每一个元素右侧小于它的元素的数量呢?


这里我们可以利用归并排序来解题。


在归并排序回溯合并之前,我们假设右区间元素都小于左区间元素,将左区间元素对应结果值都加上右区间元素数量。


在合并过程中,将左区间元素插入结果数组中时,如果此时右区间有未处理的元素,那它们肯定是大于当前左区间元素的,此时需要将当前左区间元素对应的结果值减去右区间未处理元素的数量。


这样,我们就得到了当前合并过程中右区间中小于左区间的元素的数量。 当归并排序完成后,就得到了每一个元素右侧小于它的元素的数量。


动画演示


网络异常,图片无法展示
|


代码实现


var countSmaller = function(nums) {
  // 获取原数组长度
  const len = nums.length,
  // 初始化temp数组座位归并排序的额外存储空间
  temp = Array(len),
  // 创建下标数组
  inds = Array(len),
  // 初始化结果数组
  res = Array(len).fill(0);
  // 初始化下标数组
  for(let i = 0;i<len;i++){
    inds[i] = i;
  }
  // 因为我们要修改当前值在结果数组对应下标位置的值
  // 所以,如果针对数值进行排序的话,排序后是无法得到该数值之前的下标的
  // 所以我们需要对下标数组进行排序
  // 归并排序
  function mergeSort(l,r){
    if(l>=r) return;
    const mid = (l+r)>>1;
    mergeSort(l,mid)
    mergeSort(mid+1,r)
    // 合并之前,假设右区间元素都小于左区间元素,给左区间元素的结果值累加右区间元素数量
    for(let i = l;i<=mid;i++){
      res[inds[i]] += r-mid
    }
    // 回溯合并过程
    let k = l,i = l,j = mid+1
    while(i<=mid || j<=r){
      if(j>r || (i<=mid && nums[inds[i]]<=nums[inds[j]])){
        // 插入左区间元素后,右区间剩余的元素一定大于它,所以要给它的结果值减去右区间剩余元素
        res[inds[i]] -= r-j+1
        temp[k++] = inds[i++]
      }else{
        temp[k++] = inds[j++]
      }
    }
    for(let i = l;i<=r;i++){
      inds[i] = temp[i]
    }
  }
  // 调用归并排序方法
  mergeSort(0,len-1)
  // 返回结果数组
  return res;
};
复制代码


至此我们就完成了 leetcode-315-计算右侧小于当前元素的个数


如有任何问题或建议,欢迎留言讨论!


相关文章
|
2月前
【力扣】-- 移除链表元素
【力扣】-- 移除链表元素
37 1
|
2月前
【LeetCode 27】347.前k个高频元素
【LeetCode 27】347.前k个高频元素
38 0
|
2月前
【LeetCode 06】203.移除链表元素
【LeetCode 06】203.移除链表元素
33 0
|
2月前
【LeetCode-每日一题】移除元素
【LeetCode-每日一题】移除元素
33 0
|
4月前
|
存储 算法
LeetCode第83题删除排序链表中的重复元素
文章介绍了LeetCode第83题"删除排序链表中的重复元素"的解法,使用双指针技术在原链表上原地删除重复元素,提供了一种时间和空间效率都较高的解决方案。
LeetCode第83题删除排序链表中的重复元素
|
4月前
|
算法 索引
LeetCode第34题在排序数组中查找元素的第一个和最后一个位置
这篇文章介绍了LeetCode第34题"在排序数组中查找元素的第一个和最后一个位置"的解题方法,通过使用双指针法从数组两端向中间同时查找目标值,有效地找到了目标值的首次和最后一次出现的索引位置。
LeetCode第34题在排序数组中查找元素的第一个和最后一个位置
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer II 082. 含有重复元素集合的组合
解决LeetCode平台《剑指 Offer II 082. 含有重复元素集合的组合》题目的Python代码实现,通过深度优先搜索算法找出所有和为特定目标值的数字组合,并在搜索过程中通过排序和跳过重复元素来避免解集中出现重复组合。
43 2
|
4月前
|
算法
LeetCode第27题移除元素
这篇文章介绍了LeetCode第27题"移除元素"的解题方法,通过使用双指针技巧,有效移除数组中特定值的元素并返回新数组的长度。
|
4月前
|
算法 索引 Python
【Leetcode刷题Python】34. 在排序数组中查找元素的第一个和最后一个位置(二分查找)
解决LeetCode "在排序数组中查找元素的第一个和最后一个位置" 问题的方法。第一种方法是使用两次二分查找,首先找到目标值的最左边界,然后找到最右边界。第二种方法是利用Python的list.index()方法,先正序找到起始位置,再逆序找到结束位置,并给出了两种方法的Python实现代码。
69 0
|
4月前
|
Python
【Leetcode刷题Python】203.移除链表元素
文章提供了三种删除链表中特定值节点的方法:迭代法、虚拟节点迭代删除法和递归法,并给出了相应的Python实现代码。
28 0