528. 按权重随机选择
😀最近新创建了个开源仓库,总结LeetCode的每日一题,目前已有C++、JavaScript语言版本,欢迎大家提供其他语言版本!
🩲仓库地址:每日一题系列
题目描述:
给定一个正整数数组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]
......
诸若此类。
解答:
C++:
解题思路:利用前缀和随机数,利用前缀和形成区间,用随机数
等可能
的产生区间内的数,用随机数rand()%num.back()产生区间内的随机数是不对的,因为这样产生区间内的随机数不是等可能的,看下图:
class Solution {
public:
mt19937 gen;
vector<int> Probability;
uniform_int_distribution<int> dis;
//利用随机数发生器
Solution(vector<int>& w):dis(1, accumulate(w.begin(), w.end(), 0)) {
partial_sum(w.begin(), w.end(), back_inserter(Probability));
}
int pickIndex() {
int num=0;
num= dis(gen);
auto pos=lower_bound(Probability.begin(), Probability.end(), num);
return pos-Probability.begin();
//return -1;
}
};