528. Random Pick with Weight

912. Random Pick with Weight

Description

Difficulty: Medium

Related Topics: Array, Math, Binary Search, Prefix Sum, Randomized

You are given a 0-indexed array of positive integers w where w[i] describes the weight of the ith index.

You need to implement the function pickIndex(), which randomly picks an index in the range [0, w.length - 1] (inclusive) and returns it. The probability of picking an index i is w[i] / sum(w).

  • For example, if w = [1, 3], the probability of picking index 0 is 1 / (1 + 3) = 0.25 (i.e., 25%), and the probability of picking index 1 is 3 / (1 + 3) = 0.75 (i.e., 75%).

Example 1:

1
2
3
4
5
6
7
8
9
Input
["Solution","pickIndex"]
[[[1]],[]]
Output
[null,0]

Explanation
Solution solution = new Solution([1]);
solution.pickIndex(); // return 0\. The only option is to return 0 since there is only one element in w.

Example 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Input
["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"]
[[[1,3]],[],[],[],[],[]]
Output
[null,1,1,1,1,0]

Explanation
Solution solution = new Solution([1, 3]);
solution.pickIndex(); // return 1\. It is returning the second element (index = 1) that has a probability of 3/4.
solution.pickIndex(); // return 1
solution.pickIndex(); // return 1
solution.pickIndex(); // return 1
solution.pickIndex(); // return 0\. It is returning the first element (index = 0) that has a probability of 1/4.

Since this is a randomization problem, multiple answers are allowed.
All of the following outputs can be considered correct:
[null,1,1,1,1,0]
[null,1,1,1,1,1]
[null,1,1,1,0,0]
[null,1,1,1,0,1]
[null,1,0,1,0,0]
......
and so on.

Constraints:

  • 1 <= w.length <= 104
  • 1 <= w[i] <= 105
  • pickIndex will be called at most 104 times.

Hints/Notes

  • 2023/08/12
  • preSum
  • binary search to find the left boundry
  • if the number doesn’t exist, we can iterpret the return as
    • where it ought to be in the array
    • the index of value > target
  • Leetcode solution(checked)

Solution

Language: C++

Cleaner solution with built in fuctions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
vector<int> preSum;

Solution(vector<int>& w) {
int n = w.size();
preSum.resize(n);
partial_sum(w.begin(), w.end(), preSum.begin());
}

int pickIndex() {
int num = rand() % preSum.back() + 1;
auto it = lower_bound(preSum.begin(), preSum.end(), num);
return distance(preSum.begin(), it);
}
};

/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(w);
* int param_1 = obj->pickIndex();
*/
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
34
35
36
37
38
39
40
class Solution {
public:
vector<int> preSum;

Solution(vector<int>& w) {
preSum.push_back(w[0]);
for (int i = 1; i < w.size(); i++) {
preSum.push_back(preSum[i - 1] + w[i]);
}
}

int pickIndex() {
int r = rand() % preSum.back() + 1;
int left = 0, right = preSum.size() - 1;
// 1, 2, 3, 5, 8
// r = 4
//
// 1. left = 2, right = 2
// preSum[mid] < 4, left = mid + 1 = 3, right = 2
// 2. left = 3, right = 3
// preSum[mid] > 4, left = 3, right = 2
while (left <= right) {
int mid = left + (right - left) / 2;
if (preSum[mid] == r) {
return mid - 1;
} else if (preSum[mid] < r) {
left = mid + 1;
} else if (preSum[mid] > r) {
right = mid - 1;
}
}
return left;
}
};

/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(w);
* int param_1 = obj->pickIndex();
*/