Google – Generate Strings Based on Probability
给一个label [A B C D], 和一个probability [0.5 0.1 0.2 0.2]表示每个label出现的概率, 要求生成一个满足概率条件的id序列。
[Solution]
思路就是每次得到一个0~1的random number,看它在哪个概率区间里。
[Solution #1]
Cumulative sum + binary search, O(logn)
要计算cumulative sum的目的是得到概率区间,比如
A的概率区间是 (0, 0.5]
B的概率区间是 (0.5, 0.6]
C的概率区间是 (0.6, 0.8]
D的概率区间是 (0.8, 1]
这样cumulative sum就是sums[] = [0.5, 0.6, 0.8, 1.0],所以每次generate一个0到1的random number之后,binary search在sums[]里找它的ceiling,对应的位置就是要输出的label。
[Solution #2]
buckets, O(1)
但有限制,每个概略只能有1位小数。,
思路就是开个size为10的array, 比如题目的例子就可以得到[A A A A A B C C D D], 然后generate一个0~9的数字输出对应label。
这样可以避免binary search在O(1)时间内从random number得到对应label。
有一点需要注意,最近在刷其他题的时候差点被坑死。简直智商被狗吃了。
Read full article from Google – Generate Strings Based on Probability
给一个label [A B C D], 和一个probability [0.5 0.1 0.2 0.2]表示每个label出现的概率, 要求生成一个满足概率条件的id序列。
[Solution]
思路就是每次得到一个0~1的random number,看它在哪个概率区间里。
[Solution #1]
Cumulative sum + binary search, O(logn)
要计算cumulative sum的目的是得到概率区间,比如
A的概率区间是 (0, 0.5]
B的概率区间是 (0.5, 0.6]
C的概率区间是 (0.6, 0.8]
D的概率区间是 (0.8, 1]
这样cumulative sum就是sums[] = [0.5, 0.6, 0.8, 1.0],所以每次generate一个0到1的random number之后,binary search在sums[]里找它的ceiling,对应的位置就是要输出的label。
[Solution #2]
buckets, O(1)
但有限制,每个概略只能有1位小数。,
思路就是开个size为10的array, 比如题目的例子就可以得到[A A A A A B C C D D], 然后generate一个0~9的数字输出对应label。
这样可以避免binary search在O(1)时间内从random number得到对应label。
但是前提是概率只能有1以为小数。要是有2位小数,就要开size为100的数组,要是有k位,就要开size为10^k的数组。[Note]
而Java array的最大长度是一个不超过Integer.MAX_VALUE的值,如果k大于10的话,就要Overflow了。
有一点需要注意,最近在刷其他题的时候差点被坑死。简直智商被狗吃了。
不是所有的cumulative sum都是递增的!如果出现负数的话就是无序的,不要看到cumulative sum就想着binary search. 这里因为是概率所以不会出现负数的情况。
public
String generateString(
char
[] label,
double
[] prob) {
int
n = label.length;
double
[] cumuProb =
new
double
[n];
cumuProb[
0
] = prob[
0
];
for
(
int
i =
1
; i < n; i++) {
cumuProb[i] = cumuProb[i -
1
] + prob[i];
}
Random rand =
new
Random();
StringBuilder sb =
new
StringBuilder();
for
(
int
i =
0
; i <
10
; i++) {
double
p = rand.nextDouble();
int
index = binarySearch(cumuProb, p);
sb.append(label[index]);
}
return
sb.toString();
}
private
int
binarySearch(
double
[] cumuProb,
double
p) {
int
l =
0
;
int
r = cumuProb.length -
1
;
while
(l <= r) {
int
mid = l + (r - l) /
2
;
if
(cumuProb[mid] == p) {
return
mid;
}
else
if
(cumuProb[mid] < p) {
l = mid +
1
;
}
else
{
r = mid -
1
;
}
}
if
(l >= cumuProb.length || r <
0
) {
return
l >= cumuProb.length? r : l;
}
return
cumuProb[l] < p? l +
1
: l;
}