力扣每日一题2021-08-30按权重随机选择


528.按权重随机选择

题目描述

给定一个正整数数组w,其中w[i]代表下标i的权重(下标从0开始),请写一个函数pickIndex,它可以随机地获取下标o,选取下标i的概率与w[i]成正比。
例如,对于w = [1, 3],挑选下标0的概率为1/(1+3)=0.25(即25%),而选取下标1的概率为3/(1+3)=0.75(即75%)。
也就是说,选取下标i的概率为w[i] / sum(w)。


示例1

输入:[“Solution”, “pickIndex”]、[[[1]], []]
输出:[null, 0]
解释:
Solution solution = new Solution([1]);
solution.pickIndex(); // 返回0,因为数组中只有一个元素,所以唯一的选择时返回下标0.


示例2

输入:[“Solution”, “pickIndex”, “pickIndex”, “pickIndex”, “pickIndex”, “pickIndex”]
[[[1, 3]], [], [], [], [], []]
输出:[null, 1, 1, 1, 1, 0]
解释:
Solution solution = new Solution([1, 3]);
solution.pickIndex(); // 返回1,返回下标1,返回该下标概率为3/4
solution.pickIndex(); // 返回1
solution.pickIndex(); // 返回1
solution.pickIndex(); // 返回1
solution.pickIndex(); // 返回0,返回下标0,返回该下标概率为1/4
由于是随机问题,允许多个答案,因此下列输出都正确:
[null, 1, 1, 1, 1, 0]
[null, 1, 1, 1, 1, 1]
[null, 1, 1, 1, 0, 0]

诸如此类。


提示

  • 1 <= w.length <= 10000
  • 1 <= w[i] <= 105
  • pickIndex将被调用不超过10000次。

思路:前缀和+二分查找

重新构建列表,从列表随机选数

题目比较不好理解,直白的讲就相当于有一个很大的列表,然后对于每个坐标i,都有w[i]个i在这个数组中,最后随即从数组里面选择一个。但是这样的思路比较浪费空间。
浪费空间解法

class Solution:

    def __init__(self, w: List[int]):
        total = sum(w)
        self.list = [i for i in range(len(w))]
        self.weight = [0] * len(w)
        for i, num in enumerate(w):
            self.weight[i] += float(num/total)
        self.picks = random.choices(self.list, self.weight, k=10000)
        self.idx = -1


    def pickIndex(self) -> int:
        self.idx += 1
        return self.picks[self.idx]



# Your Solution object will be instantiated and called as such:
# obj = Solution(w)
# param_1 = obj.pickIndex()

前缀和+二分查找

假定第一个坐标有k0个,那么占用的区间为[1, k0],假定第二个坐标有k1个,占用的区间为[k0+1, k0+k1],这个时候我们生成一个随机数在区间[]1, k0+k1],落在第一个坐标的区间概率为k0/(k0+k1)。并且随机数可以通过二分查找找到对应的原坐标。
前缀和+二分查找

class Solution:

    def __init__(self, w: List[int]):
        # 计算前缀和
        self.presum = list(accumulate(w))


    def pickIndex(self) -> int:
        rand = random.randint(1, self.presum[-1])
        return bisect_left(self.presum, rand)



# Your Solution object will be instantiated and called as such:
# obj = Solution(w)
# param_1 = obj.pickIndex()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值