Leetcode 528. 按权重随机选择(中等) 前缀和数组+二分查找左侧边界

labuladong讲解

528. 按权重随机选择(中等)

题目:

 

 思路:

对于[1,7],我们可以将其膨胀为长度为[1,7]的线段,而后产生[1,7]的int随机数x,当x落在1时返回0,当x落在2-7时返回1.实现等概率。

扩展的线段,可以用前缀和数组表示。

查找与x最接近的左侧数值时可以使用二分查找左侧边界实现。

返回时注意left-1,因为presum的id右移了一位

class Solution {
public:
    Solution(vector<int>& w) {
        int n=w.size();
        // 构建前缀和数组,偏移一位留给 preSum[0]
        presum.resize(n+1);
        for(int i=1;i<=n;++i){
            // preSum[i] = sum(w[0..i-1])
            presum[i]=presum[i-1]+w[i-1];
        }
    }
    
    int pickIndex() {
        // 在闭区间 [1, preSum[n - 1]] 中随机选择一个数字
        int index=rand()%presum.back()+1;
        // 获取 target 在前缀和数组 preSum 中的索引
        // 搜索左侧边界的二分搜索
        int left=1,right=presum.size()-1;
        while(left<=right){
            int mid=left+(right-left)/2;
            if(presum[mid]<index){
                left=mid+1;
            }
            else if(presum[mid]>index){
                right=mid-1;
            }
            else{
                right=mid-1;
            }
        }
        // preSum 的索引偏移了一位,还原为权重数组 w 的索引
        return left-1;
    }
    // 前缀和数组
    vector<int> presum;
};

 

posted @ 2022-02-28 15:31  鸭子船长  阅读(54)  评论(0编辑  收藏  举报