- 思路
构造前缀和数组,在0~sum中生成一个随机数,找第一个严格大于随机生成数x的数,这个数对应的下标就是要找的下标。
前缀和数组presum,presum[i]与前一位置的前缀和presum[i-1]相减正好的下标i对应的数,也就是下标i的权值,就相当于以长度代表概率,对于任意一个x,他严格小于最小前缀和presum[i],表示他在[presum[i-1],presum[i]]区间内,区间长度:presum[i]-presum[i-1] = w[i],随机数一共有sum种情况,在以上区间的情况为w[i]个,所以下标i的概率为w[i]/sum;
要找到第一个严格大于x的数,对前缀和数组presum进行二分查找(presum是递增的)O(logn) - 代码
class Solution {
private:
vector<int> presum;
int len;
public:
Solution(vector<int>& w) {
len = w.size();
presum.resize(len);
presum[0] = w[0];
for(int i = 1;i<len;++i){
presum[i] = presum[i-1] + w[i];
}
}
int pickIndex() {
int left = 0,right = len-1;
int x = rand()%presum[right];
while(left < right){
int mid = left + (right-left)/2;
if(x < presum[mid]) right = mid;
else left = mid+1;
}
return left;
}
};
- 总结学习
1:怎么得出概率?以长度代替概率,本题是前缀和数组划分区间,每一个前缀和与之前的前缀和构成一个长度为w[i]的区间,对于随机数,在该区间的概率正好就是w[i]/sum
2:生成一个在0~sum的随机数 rand()%sum