528 按权重随机选择(概率、前缀和、二分查找)

41 篇文章 0 订阅
18 篇文章 0 订阅

1. 问题模式:

给定一个正整数数组 w ,其中 w[i] 代表下标 i 的权重(下标从 0 开始),请写一个函数 pickIndex ,它可以随机地获取下标 i,选取下标 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]
[null,1,1,1,0,1]
[null,1,0,1,0,0]
......
诸若此类。
提示:
1 <= w.length <= 10000
1 <= w[i] <= 10 ^ 5
pickIndex 将被调用不超过 10000 次
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/random-pick-with-weight

2. 思路分析:

我们可以将每一个数字看成是一段一维中的线段,通过随机函数随机出当前的数字x并且计算出当前的数字x判断落在哪一段线段上,可以发现前缀和表示的就是落在哪一个线段,所以我们只需要找出当前的随机数x落在前缀和对应的哪一个区间,也即需要在前缀和数字s中找出第一个大于等于x的位置即可,查找第一个大于等于x的位置可以使用二分查找。

3. 代码如下:

from typing import List
import bisect
import random


class Solution:
    s = None

    def __init__(self, w: List[int]):
        n = len(w)
        s = [0] * n
        s[0] = w[0]
        for i in range(1, n):
            s[i] += s[i - 1] + w[i]
        self.s = s


    def pickIndex(self) -> int:
        s = self.s
        # 随机出1~s[-1]的数字
        x = random.randint(0, s[-1] - 1) + 1
        # 使用bisect查找第一个大于等于x的位置, 区间的下标就是我们需要求解的答案
        return bisect.bisect_left(s, x)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值