排序篇 - leetcode 315.计算右侧小于当前元素的个数(hard)

1. 题目描述

跳转至 leetcode 作答界面

给你一个整数数组 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 个更小的元素

提示:

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

2. 思路/题解

2.1 思考核心

💡 如何统计每一个元素的右边到底有多少个元素比自己小

2.2 方法步骤

概述

将原数组构建成带有索引的二维数组,在降序归并排序的合并过程中维护结果数组

做本题之前可以先复习一下归并排序,然后做一下 LCR 170.交易逆序对的总数 ,LCR 170 相对简单一些,它是在归并排序的合并过程中维护「结果变量」,而本题要维护的则是「结果数组」

🎈 复习归并排序 + LCR 170 题解

重点

  • 由于在合并过程中需要不断维护结果数组,这就需要利用好索引,因此可以在排序前先将原输入数组构建成带有索引的二维数组。

    # 将原输入数组构建成带有索引的数组
    numsarr = [[nums[i], i] for i in range(n)]

  • 统计 nums[i] 的右侧有多少小于它的元素👉降序归并排序的合并过程中,如果发现 nums[i] > nums[j] , 由于 nums[j...right] 已经降序排列好,那显然 nums[j...right] 都是小于 nums[i] 且位于 nums[i] 右侧的元素,一共有 right - j + 1 个,它们都应被更新到「结果数组」中。

        下面用一张图来说明红字内容

      

2.3 具体代码

class Solution:
    def __init__(self):
        self.tmp = []

    def countSmaller(self, nums: List[int]) -> List[int]:
        n = len(nums)
        numsarr = [[nums[i], i] for i in range(n)]
        res = [0] * n
        self.tmp = [[nums[i],i] for i in range(n)]

        def mergeSort(left, right):
            if left >= right:
                return
            mid = (left + right) // 2
            mergeSort(left, mid)
            mergeSort(mid + 1, right)
            
        	# 归并排序需要额外的空间
            self.tmp[left : right + 1] = numsarr[left : right+1]
            i , j , k = left, mid +1, left

            # 因为是降序排列,始终将比较下来更大的元素拿下来
            while i <= mid and j <= right:
                if self.tmp[j][0] >= self.tmp[i][0]:
                    numsarr[k] = self.tmp[j]
                    j += 1
                else:
                    numsarr[k] = self.tmp[i]
                    i += 1
                    # 更新结果值, 因为此时 tmp[i][0] 的值比 tmp[j:right+1][0] 的值都大
                    res[numsarr[k][1]] += right - j + 1
                k += 1
            # 说明右边的一半走完了,左边剩下的都是小于右边的,直接填进去就好
            if i <= mid:
                numsarr[k: right+1] = self.tmp[i:mid+1] 

            else:
                numsarr[k: right+1] = self.tmp[j:right+1]

        mergeSort(0,n-1)
        return res

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值