📌  相关文章
📜  数组中每个元素右侧较大元素的计数(1)

📅  最后修改于: 2023-12-03 14:54:59.545000             🧑  作者: Mango

数组中每个元素右侧较大元素的计数

在一个整数数组 nums 中,对于每个 nums[i],请计算出它右侧比它大的元素数量。

示例:

输入:nums = [5,2,6,1] 输出:[2,1,1,0] 解释: 5 的右侧有 2 个比它大的数(6 和 44)。 2 的右侧仅有 1 个比它大的数(6)。 6 的右侧仅有 1 个比它大的数(44)。 1 的右侧没有比它大的数。

解法

该问题可以用暴力求解,我们可以使用嵌套循环,对于每个数 check 所有的右侧元素是否比他大,如果是,那么 count++。

下面是 python3 的代码片段:

def countSmaller(nums):
    counts = []
    for i in range(len(nums)):
        count = 0
        current = nums[i]
        for j in range(i+1, len(nums)):
            if nums[j] > current:
                count += 1
        counts.append(count)
    return counts

该算法的时间复杂度为 $O(n^2)$,不是最优解法,但是可以用来帮助我们更好地理解问题。

更高效的解法是使用归并排序算法。首先我们需要给 nums 数组排序,并记录每个数的原始下标。我们从数组的右侧开始遍历已排序的数,对于每个数,我们都可以用一个计数器记录其右侧比它大的元素数量,并将这个计数器赋值给结果数组 num_counts 中对应的位置。具体实现可以看下面的代码:

def countSmaller(nums):
    def merge_sort(enum):
        mid = len(enum) // 2
        if mid:
            left, right = merge_sort(enum[:mid]), merge_sort(enum[mid:])
            for i in range(len(enum))[::-1]:
                if not right or left and left[-1][1] > right[-1][1]:
                    smaller[left[-1][0]] += len(right)
                    enum[i] = left.pop()
                else:
                    enum[i] = right.pop()
        return enum
    smaller = [0] * len(nums)
    merge_sort(list(enumerate(nums)))
    return smaller

在该版本中,我们使用了归并排序算法。我们首先将enumerate(nums)中的每个数变成一个有序的数对,其中第一个元素是原数组nums中的数对应的下标,第二个元素是原数组nums中的数。我们然后按照 数组中第二个元素的大小 对整个数组排序。在排序过程中,我们对于每个数 check 排序后的数组的右侧,如果右侧的数比它大,那么这个数的下标对应的结果数组 smaller 中值就应该加一。 最后我们返回 smaller 数组。

这个算法的时间复杂度为 $O(n \log n)$,因为我们使用了归并排序算法,最坏情况下需要进行的操作次数的上界是 $n \log n$,所以时间复杂度是 $O(n \log n)$。