315.计算右侧小于当前元素的个数(二分搜索)

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

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

示例1:

输入:nums = [5,2,6,1]
输出:[2,1,1,0]

示例2:

输入:[-1]
输出:[0]

示例3:

输入:[-1,-1]
输出:[0,0]

提示:
  • 1 < = n u m s . l e n g t h < = 1 0 5 1<=nums.length<=10^5 1<=nums.length<=105
  • − 1 0 4 < = n u m s [ i ] < = 1 0 4 -10^4<=nums[i]<=10^4 104<=nums[i]<=104

超时尝试

1、暴力搜索

最简单直观的方法就是对每一个元素进行遍历搜索。但该题的难度标注为困难,使用暴力搜索一定会导致超时。尝试结果:超出时间限制。

2、逆序遍历,记录各元素前一次的索引

对暴力搜索进行优化:假设一个元素x出现了多次,其中x1和x2(x1<x2)是其两次出现的下标。进行逆序遍历,当遍历到x1时,x2一定已经得到正确的count2,此时只需要统计(x1,x2)之间小于x的元素个数count(x1,x2),在加上count2,就能得到x1右侧小于x的元素个数count1。
对于存在大量重复元素的数组,该方法应该能取得较好的效果,但由于该题给出的元素范围为 [ − 1 0 4 , 1 0 4 ] [-10^4,10^4] [104,104],元素重复的概率仍然很小,该方法效果可能相较暴力搜索提升不大,在数组无重复元素时等同于暴力搜索。尝试结果:超出时间限制。
对索引x1,x2,如果nums[x1]=nums[x2],显然counts[x1]=counts[x2]+count(x1,x2);但当nums[x1]<>nums[x2]时,counts[x1]与counts[x2]之间缺少一种明确的关系,因此动态规划算法不适合用于解决该问题。

3、逆序遍历,二分插入

从数组后端进行遍历,每次将一个元素x放入另一个列表中,利用二分查找搜索其应该插入的位置(相同则插入到相同元素的最左端),这个位置对应的索引等于原数组中右侧小于x的元素数量。
尝试结果:超出时间限制。挂在了倒数第二个测试样例,特征为大量重复元素。由于在处理相同元素时,采用的是逐个向前遍历的方式,在存在大量重复元素时处理效率较低。接下来需要对寻找插入相同元素的位置进行优化。

成功代码(二分插入)

经过上述尝试,现在所需要进行的优化就是寻找相同元素的插入位置。由于需要将x插入到相同元素的最前端,因此在使用二分法时,将大于和等于归为同一类即可。

class Solution:
    def countSmaller(self, nums: List[int]) -> List[int]:
        def find(num):
            left, right = 0,len(sortlist)
            while left < right:
                mid = (left + right) // 2
                if sortlist[mid] < num:
                    left = mid + 1
                elif sortlist[mid] >= num:
                    right = mid
            sortlist.insert(left,num)
            return left
            
        length = len(nums)
        counts = [0]*length
        sortlist = [nums[-1]]
        for i in range(length-2,-1,-1):
            counts[i] = find(nums[i])
        return counts

该方法成功通过测试。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值