题目链接:LCR 071. 按权重随机选择 - 力扣(LeetCode)
题目:
给定一个正整数数组 w,其中 w[i] 代表下标 i 的权重(下标从 0 开始),请写一个函数 pickIndex,它可以随机地获取下标 i,选取下标 i 的概率与 w[i] 成正比。
例如,对于 w = [1, 2, 3, 4],选取下标 0 的概率为 1 / (1 + 2 + 3 + 4) = 0.1(即 10%),选取下标 1 的概率为 2 / 10 = 0.2(即 20%),选取下标 3 的概率为 3 / 10 = 0.3(即 30%),选取下标 4 的概率为 4 / 10 = 0.4(即 40%)。
分析:
创建一个和权重数组 w 的长度一样的数组 sums,其中 sums[i] 是权重数组中前 i 个数字之和。例如,累加权重数组 [1, 2, 3, 4] 中的权重得到的数组 sums 为 [1, 3, 6, 10]。
有了这个累加权重的数组之后,等概率地生成 1 到 10 之间的一个随机数 p,如果 p <= 1,则选取下标 0;如果 1 < p <= 3,则选取下标 1;如果 3 < p <= 6,则选取下标 2;如果 6 < p <= 10,则选取下标 3。
也就是说,随机生成 p 之后,找到数组 sum 中第一个大于或等于 p 的值,然后选取它对应的下标。
代码实现:
class Solution {
public:
Solution(vector<int>& w) {
int n = w.size();
sum.resize(n);
sum[0] = w[0];
for (int i = 1; i < n; ++i)
{
sum[i] = w[i] + sum[i - 1];
}
}
int pickIndex() {
int p = rand() % sum.back() + 1;
int left = 0;
int right = sum.size() - 1;
while (left < right)
{
int mid = (left + right) / 2;
if (sum[mid] < p)
left = mid + 1;
else // sum[mid] >= p
right = mid;
}
return right;
}
private:
vector<int> sum;
};