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

发布于 2023-02-14  100 次阅读


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

难度

  • Easy
  • Medium
  • Hard

思路

剑指 Offer 51. 数组中的逆序对 非常相似,所以也用归并排序来写。

不同之处在于,本题要求知道每一个数对应的右侧逆序数的数目。

用笨一点的方法,在排序的同时,维护一个数组 cnt ,记录每个数字右侧的逆序数的数量。cnt 要跟着 nums 一起排序,所以最后不能直接返回 cnt ,还要根据下标进行还原。故此,还需要一个 indices 数组用于记录当前位置的下标对应于原始顺序的下标。

此外,需要几个 temp 数组用于辅助。

还可以用别的方法,如二分(可能超时了),树状数组(待学习),线段树。

代码

class Solution:
    def countSmaller(self, nums: List[int]) -> List[int]:
        n = len(nums)
        cnt = [0 for _ in range(n)]
        temp_nums = list(nums)
        temp_cnt = list(cnt)
        indices = list(range(n))
        temp_indices = list(indices)

        def merge(l: int, r: int) -> None:
            if l >= r: return
            mid = (l + r) >> 1
            merge(l, mid)
            merge(mid + 1, r)
            L, R, cur = l, mid + 1, l
            while L <= mid and R <= r:
                if nums[L] <= nums[R]:
                    temp_nums[cur] = nums[L]
                    temp_cnt[cur] = cnt[L] + R - mid - 1
                    temp_indices[cur] = indices[L]
                    L += 1
                else:
                    temp_nums[cur] = nums[R]
                    temp_cnt[cur] = cnt[R]
                    temp_indices[cur] = indices[R]
                    R += 1
                cur += 1
            while L <= mid:
                temp_nums[cur] = nums[L]
                temp_cnt[cur] = cnt[L] + R - mid - 1
                temp_indices[cur] = indices[L]
                L += 1
                cur += 1
            while R <= r:
                temp_nums[cur] = nums[R]
                temp_cnt[cur] = cnt[R]
                temp_indices[cur] = indices[R]
                R += 1
                cur += 1

            nums[l:r + 1] = temp_nums[l:r + 1]
            cnt[l:r + 1] = temp_cnt[l:r + 1]
            indices[l:r + 1] = temp_indices[l:r + 1]
            return

        merge(0, n - 1)
        ans = [0 for _ in range(n)]
        for i in range(n):
            ans[indices[i]] = cnt[i]
        return ans