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

58 阅读2分钟

题目

给你一个整数数组 nums **,按要求返回一个新数组 counts **。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

示例 1:

输入: nums = [5,2,6,1]
输出: [2,1,1,0] 
解释: 
5 的右侧有 2 个更小的元素 (21)
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