Random Pick with Weight

medium math binary search prefix sum randomized

Problem

Given an array w where w[i] is the weight of index i, implement pickIndex() so that i is returned with probability w[i] / Σw.

Inputw = [1, 3], target = 2
Output1
Prefix = [1, 4]; first prefix ≥ 2 is at index 1.

import random
from bisect import bisect_left

class Solution:
    def __init__(self, w):
        self.prefix = []
        total = 0
        for x in w:
            total += x
            self.prefix.append(total)
        self.total = total

    def pickIndex(self):
        t = random.randint(1, self.total)
        return bisect_left(self.prefix, t)
class Solution {
  constructor(w) {
    this.prefix = [];
    let total = 0;
    for (const x of w) { total += x; this.prefix.push(total); }
    this.total = total;
  }
  pickIndex() {
    const t = Math.floor(Math.random() * this.total) + 1;
    let lo = 0, hi = this.prefix.length - 1;
    while (lo < hi) {
      const mid = (lo + hi) >> 1;
      if (this.prefix[mid] < t) lo = mid + 1;
      else hi = mid;
    }
    return lo;
  }
}
class Solution {
    int[] prefix;
    int total;
    Random rand = new Random();
    public Solution(int[] w) {
        prefix = new int[w.length];
        int s = 0;
        for (int i = 0; i < w.length; i++) { s += w[i]; prefix[i] = s; }
        total = s;
    }
    public int pickIndex() {
        int t = rand.nextInt(total) + 1;
        int lo = 0, hi = prefix.length - 1;
        while (lo < hi) {
            int mid = (lo + hi) >>> 1;
            if (prefix[mid] < t) lo = mid + 1;
            else hi = mid;
        }
        return lo;
    }
}
class Solution {
    vector<int> prefix;
    int total;
public:
    Solution(vector<int>& w) {
        int s = 0;
        for (int x : w) { s += x; prefix.push_back(s); }
        total = s;
    }
    int pickIndex() {
        int t = rand() % total + 1;
        return lower_bound(prefix.begin(), prefix.end(), t) - prefix.begin();
    }
};
Time: O(n) init, O(log n) pick Space: O(n)