forked from rampatra/Algorithms-and-Data-Structures-in-Java
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReservoirSampling.java
65 lines (56 loc) · 2.09 KB
/
ReservoirSampling.java
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.rampatra.arrays;
import java.util.Arrays;
import java.util.Random;
/**
* Created by IntelliJ IDEA.
*
* @author rampatra
* @since 7/21/15
* @time: 2:52 PM
*/
public class ReservoirSampling {
/**
* Returns {@param k} non-repeating random numbers from {@param stream}
* using reservoir sampling method.
* <p/>
* Explanation:
* 1) Create an array reservoir[0..k-1] and copy first k items of stream[] to it.
* 2) Now one by one consider all items from (k+1)th item to nth item.
* a) Generate a random number from 0 to i where i is index of current item in
* stream[]. Let the generated random number is j.
* b) If j is in range 0 to k-1, replace reservoir[j] with arr[i].
* <p>
* In the above procedure, we are computing random number for each of the indexes greater than k
* thereby giving all items an equal probability.
* <p>
* NOTE: When {@param k} is small enough we can use a simpler method as follows:
* Create an array reservoir[] of maximum size k. One by one randomly select an
* item from stream[0..n-1]. If the selected item is not previously selected, then
* put it in reservoir[]. To check if an item is previously selected or not, we
* need to search the item in reservoir[].
* The time complexity of this algorithm will be O(k^2). This can be costly
* if k is big. Also, this is not efficient if the input is in the form of a stream.
*
* @param stream
* @param k
* @return
*/
public static int[] getKRandomNumbers(int[] stream, int k) {
int i;
int[] reservoir = new int[k];
for (i = 0; i < k; i++) {
reservoir[i] = stream[i];
}
for (; i < stream.length; i++) {
int rand = new Random().nextInt(i);
if (rand < k) {
reservoir[rand] = stream[i];
}
}
return reservoir;
}
public static void main(String[] args) {
int[] stream = {1, 2, 3, 4, 5, 6, 7, 8, 9};
System.out.println(Arrays.toString(getKRandomNumbers(stream, 4)));
}
}