题目
给你一个整数数组 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
思路
解法一: 归并merge + 索引数组
将数组不断划分,直到只有1个数字;然后将左右区间进行判断,得出右侧小于当前元素的个数,然后从左边的数值依次找到右边第一个比这个大的值位置,计算右边比左边小的长度,然后将两个区间排序后返回。
为什么需要索引数组?
在归并排序中,数组的元素的位置在merge后会发生变化,这样就会导致我们计算本题的结果出现问题。所以需要一个索引数组,不妨设为index,保存当前元素的在数组中的原始位置,对原始位置的元素进行求值.
代码一: 归并merge+索引数组
class Solution:
def countSmaller(self, nums: List[int]) -> List[int]:
def merge(nums, l, r):
if l >= r:
return
mid = l + ((r-l) >> 1)
left = merge(nums, l, mid)
right = merge(nums, mid+1, r)
i = l
j = mid + 1
tmp = []
while i <= mid and j <= r:
if nums[index[i]] <= nums[index[j]]:
tmp.append(index[i])
res[index[i]] += j - mid - 1
i += 1
else:
tmp.append(index[j])
j += 1
while i <= mid:
tmp.append(index[i])
res[index[i]] += j - mid - 1
i += 1
while j <= r:
tmp.append(index[j])
j += 1
index[l:r+1] = tmp
n = len(nums)
res = [0] * n
if n <= 1:
return res
index = list(range(n))
merge(nums, 0, n-1)
return res