1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Solution { private int[] indexLimit; private Random rand;
public Solution(int[] w) { indexLimit = new int[w.length]; rand = new Random(); int sum = 0; for (int i = 0; i < w.length; i++) { sum += w[i]; indexLimit[i] = sum; } }
public int pickIndex() { int selection = rand.nextInt(indexLimit[indexLimit.length - 1]) + 1; return binarySearch(indexLimit, selection); }
private int binarySearch(int[] indexLimit, int selection) { int left = 0, right = indexLimit.length - 1, ans = indexLimit.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (indexLimit[mid] < selection) { left = mid + 1; } else { ans = mid; right = mid - 1; } } return ans; } }
|
使用accumulated sum的方法. 给的w数组中, 每个元素的值代表当前index的weight. 我们不妨这样: 假设给我们的w为[2, 4, 2, 3, 1]. 那么index 0分配到数轴上1和2这两个数字; index 1分配到3, 4, 5, 6四个数字; index 2分配到7, 8两个数字; index 3分配到9, 10, 11三个数字; index 4分配到12这个数字.然后我们在1到12任意取数字, 看取到的数字落在了哪一个index包含的区间内即可.
于是我们用一个数组记录每一个index的上届(inclusive)是什么, 因为下届就是index - 1的上届再 + 1. 比如index 0的上届是2, index 1的是6, index 2的是8, index 3的是11, index 4的是12. 这样这个数组就是: [2, 6, 8, 11, 12]. 我们可以用一个变量sum, 不断地累加w[i], 赋值给相应位置的元素然后来创建这样的数组.
这道题的精髓就是数轴. 给每一个index分配它weight个数的数轴上的点. 从1开始依次给每个index分配.
rand.nextInt(bound) 产生的数字的范围在[0, bound)中. 这样就理解第16行为什么要 + 1了.
时间复杂度: O(n) (创建新数组需要遍历w这个数组).
空间复杂度: O(n) (创建新数组需要空间)