Skip to main content

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

标签: array, binary-indexed-tree, binary-search, divide-and-conquer

难度: Hard

通过率: 42.65%

原题链接: https://leetcode.com/problems/count-of-smaller-numbers-after-self/description/

题目描述

给定一个整数数组 nums,返回一个整数数组 counts,其中 counts[i] 表示 nums[i] 右侧小于 nums[i] 的元素个数。

解题思路

此问题可以通过二分思想结合归并排序来解决。首先,从右到左遍历数组,这样可以在生成结果时保持计算顺序;其次,在遍历过程中对于每个元素 nums[i],通过归并排序的方法定位该元素在已排序序列中的位置,这样即可实现对右侧小元素的计数。具体步骤如下:

  1. 对数组 nums 按索引进行归并排序。
  2. 在归并过程中维护一个计数数组 counts 来记录每个元素右侧小于它的元素数量。
  3. 使用归并排序的性质,左数组中的元素与右数组比大小时,若 nums[left] > nums[right],说明 left 位置的元素比 right...ounts 中对应位置的计数。
  4. 归并排序完成后,counts 就是结果。

这样,通过分治策略,每次分割处理一半数组,可以高效地完成整个计数过程。

代码实现

class Solution:
def countSmaller(self, nums):
# 首先处理输入的索引和初始化计数
counts = [0] * len(nums)
indexed_nums = list(enumerate(nums))

def merge_sort(enum):
half = len(enum) // 2
if half:
left, right = merge_sort(enum[:half]), merge_sort(enum[half:])
for i in range(len(enum) - 1, -1, -1):
if not right or left and left[-1][1] > right[-1][1]:
counts[left[-1][0]] += len(right)
enum[i] = left.pop()
else:
enum[i] = right.pop()
return enum

merge_sort(indexed_nums)
return counts

复杂度分析

时间复杂度为 O(nlogn)O(n \log n),其中 nn 是数组的长度。归并排序在最坏情况下是线性对数复杂度。

空间复杂度为 O(n)O(n),主要用于存储辅助数组和索引数组。