《LeetCode之每日一题》:135.按权重随机选择

Posted 是七喜呀!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《LeetCode之每日一题》:135.按权重随机选择相关的知识,希望对你有一定的参考价值。

按权重随机选择


题目链接: 按权重随机选择

有关题目

给定一个正整数数组 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

题解

Tips
参考官方题解下烂柯人

C++STL说明:

 1. mt19937头文件是<random> 是伪随机数产生器,用于产生高性能的随机数
 2. uniform_int_distribution 头文件在<random>中,是一个随机数分布类,参数为生成随机数的类型,构造函数接受两个值表示区间段
 3. accumulate 头文件在<numeric>中,求特定范围内所有元素的和。
 4. partial_sum函数的头文件在<numeric>,对(first, last)内的元素逐个求累计和,放在result容器内
 5. back_inserter函数头文件<iterator>,用于在末尾插入元素。
 6. lower_bound头文件在<algorithm>,用于找出范围内不小于num的第一个元素
 7. random_device生成真随机数

真随机数和伪随机数
法一:前缀和 + 二分查找

思路见官方题解
C++

class Solution {
private:
    mt19937 gen;
    uniform_int_distribution<int> dis;
    vector<int> pre;
public:
    Solution(vector<int>& w): gen(random_device{}()), dis(1, accumulate(w.begin(), w.end(), 0)) {
        partial_sum(w.begin(), w.end(), back_inserter(pre));
    }
    
    int pickIndex() {
        int x = dis(gen);//生成符合范围的真随机数
        return lower_bound(pre.begin(), pre.end(), x) - pre.begin();
    }
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(w);
 * int param_1 = obj->pickIndex();
 */


C

typedef struct {
    int* pre;
    int preSize;
    int total;
} Solution;


Solution* solutionCreate(int* w, int wSize) {
    Solution* obj = (Solution*)malloc(sizeof(Solution));
    obj->pre = (int*)malloc(sizeof(int) * wSize);
    obj->preSize = wSize;
    obj->total = 0;
    for (int i = 0; i < wSize; ++i){
        obj->total += w[i];
        if (i > 0){
            obj->pre[i] = obj->pre[i - 1] + w[i];
        }
        else {
            obj->pre[i] = w[i]; 
        }
    }
    return obj;
}
int binarySearch(Solution* obj, int target){
    int l = 0, r = obj->preSize - 1;
    while(l < r){
        int mid = l + r >> 1;
        if (obj->pre[mid] < target){
            l = mid + 1;
        }
        else {
            r = mid;
        }
    }
    return l;
}
int solutionPickIndex(Solution* obj) {
    int x = rand() % obj->total + 1;
    return binarySearch(obj, x);
}

void solutionFree(Solution* obj) {
    free(obj->pre);
    free(obj);
}

/**
 * Your Solution struct will be instantiated and called as such:
 * Solution* obj = solutionCreate(w, wSize);
 * int param_1 = solutionPickIndex(obj);
 
 * solutionFree(obj);
*/

以上是关于《LeetCode之每日一题》:135.按权重随机选择的主要内容,如果未能解决你的问题,请参考以下文章

《LeetCode之每日一题》:220.随机翻转矩阵

《LeetCode之每日一题》:204.数字范围按位与

《LeetCode之每日一题》:139.用 Rand7() 实现 Rand10()

《LeetCode之每日一题》:215.打乱数组

《LeetCode之每日一题》:35. 前K个高频单词

《LeetCode之每日一题》:274.合并两个有序数组