528.按权重随机选择

386 阅读2分钟

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;
    }
};