QUESTION:
Given an array w of positive integers, where w[i] describes the weight of index i, write a function pickIndex which randomly picks an index in proportion to its weight.
Note:
1 <= w.length <= 10000
1 <= w[i] <= 10^5
pickIndex will be called at most 10000 times.
Example 1:
Input:
["Solution","pickIndex"]
[[[1]],[]]
Output: [null,0]
Example 2:
Input:
["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"]
[[[1,3]],[],[],[],[],[]]
Output: [null,0,1,1,1,0]
Explanation of Input Syntax:
The input is two lists: the subroutines called and their arguments. Solution’s constructor has one argument, the array w. pickIndex has no arguments. Arguments are always wrapped with a list, even if there aren’t any.
EXPLANATION:
这道题目其实还是挺容易的,就是题意比较难以理解。先说一下题意吧:给定一个数组,每个数字表示权重,调用pick的时候,产出的数字,符合权重。比如第二个例子,1+3 = 4,意思是pick输出index 0的概率是0.25,而输出1的概率是0.75.这样就很好理解了。
思路肯定就是:先算出对应的和sum,然后再通过随机函数来获取到随机数,查看这个随机数的对应的index。一开始的思路就是:直接创建一个数组sum,sum[index]就是对应的值,如第二个例子就是: 【0,1,1,1】这样,比如我随机1,2,3的时候,就是权重3的索引,但是这个一提交,就提示我内存溢出,哈哈,看来只能想其他办法了。现在问题就处在查找到对应的索引,其实没有必要将每个索引都给一个位置,这样虽然可以拿到线性的时间复杂度,但是空间复杂度太大了。可以只保存每个权重开头的数字,这样在pick的时候,就可以判断开头的位置来获取到索引了。
思路:
- 堆w进行求和,同时标记索引位置
- 随机产生数
- 将产生的数在索引中找位置(优化点,采用二分查找法
- 第一个小于这个的,就是对应的位置
SOLUTION:
class Solution {
Random r;
int[] ints;
int sum;
public Solution(int[] w) {
ints = new int[w.length];
for(int i = 0;i<w.length;i++){
sum+=w[i];
ints[i] = sum;
}
r = new Random(sum);
}
public int pickIndex() {
int random = r.nextInt(sum);
for(int i = 0;i<ints.length;i++){
if(random<ints[i]) return i;
}
return 0;
}
}