给你一个 下标从 0 开始 的正整数数组 w ,其中 w[i] 代表第 i 个下标的权重。
请你实现一个函数 pickIndex ,它可以 随机地 从范围 [0, w.length - 1] 内(含 0 和 w.length - 1)选出并返回一个下标。选取下标 i 的 概率 为 w[i] / sum(w) 。
例如,对于 w = [1, 3],挑选下标 0 的概率为 1 / (1 + 3) = 0.25 (即,25%),而选取下标 1 的概率为 3 / (1 + 3) = 0.75(即,75%)。
示例 1:
输入:
["Solution","pickIndex"]
[[[1]],[]]
输出:
[null,0]
解释:
Solution solution = new Solution([1]);
solution.pickIndex(); // 返回 0,因为数组中只有一个元素,所以唯一的选择是返回下标 0。
思路:前缀和数组+左侧边界的二分查找
当目标元素 target
不存在数组 nums
中时,搜索左侧边界的二分搜索的返回值可以做以下几种解读:
1、返回的这个值是 nums
中大于等于 target
的最小元素索引。
2、返回的这个值是 target
应该插入在 nums
中的索引位置。
3、返回的这个值是 nums
中小于 target
的元素个数。
比如在有序数组 nums = [2,3,5,7]
中搜索 target = 4
,搜索左边界的二分算法会返回 2,带入均正确。
class Solution {
public:
vector<int> presum;
Solution(vector<int>& w) //得到前缀和数组
{
presum.resize(w.size()+1,0);
for(int i=1;i<presum.size();i++)
{
presum[i]=presum[i-1]+w[i-1];
}
}
int pickIndex() {
int n=presum.size();
int t=(rand()%presum[n-1])+1;
int left=1,right=n;
while(left<right)//左侧边界的二分查找
{
int mid=(left+right)/2;
if(presum[mid]==t)
{
right=mid;
}
else if(presum[mid]>t)
{
right=mid;
}
else if(presum[mid]<t)
{
left=mid+1;
}
}
return left-1;
}
};
举例:w = [1, 3]
presum=[0,1,4] 1<=target<=4
若target等于2/3/4则在presum中大于等于2/3/4的最小值为4,返回下标2,又因为对应w中的下标1,所以返回1;
若target等于1则在presum中大于等于1的最小值为1,返回下标1,又因为对应w中的下标0,所以返回0;