[英]Randomly pick k bits out of n from a Java BitSet
如何從長度為m
的Java BitSet中選擇k
位, n
位打開,其中k≤n≤m
?
輸入示例: m=20, n=11
輸出示例: k=3
選擇一個隨機數0≤ i ≤ m-1
如果它在輸入上打開而未在輸出上打開,則在輸出中打開它,直到輸出中的k
位打開。
當n
遠小於m
時,這種方法失敗。 還有其他想法嗎?
您可以從第一位掃描到最后一位,並將儲存采樣應用於設置的位。
該算法具有O(m)
時間復雜度,並且需要O(k)
存儲器。
如果約束允許,您可以通過以下方式解決任務:
構造一個包含所有設置位索引的List
。 Collections#shuffle
就可以了。 從隨機列表中選擇前k
索引。
編輯根據評論,如果k
非常小,則該算法效率低,而n
很大。 這是另一種選擇:在區間[0, n]
生成k
隨機的不同數字。 如果在生成數字時,數字已經存在於所選索引集中,則執行鏈接方法:即將數字增加1,直到得到集合中尚未出現的數字。 最后生成的索引是您在設置位中選擇的索引。
如何找到所有設置位的n
位置並將它們作為第一步放入集合中,然后從該集合中隨機選擇k
位置?
如果n
比k
大得多,你可以在選擇盡可能多的算法之后減去Fisher-Yates shuffle算法:
private static Random rand = new Random();
public static BitSet chooseBits(BitSet b, int k) {
int n = b.cardinality();
int[] indices = new int[n];
// collect indices:
for (int i = 0, j = 0; i < n; i++) {
j=b.nextSetBit(j);
indices[i] =j++;
}
// create returning set:
BitSet ret = new BitSet(b.size());
// choose k bits:
for (int i = 0; i<k; i++) {
//The first n-i elements are still available.
//We choose one:
int pick = rand.nextInt(n-i);
//We add it to our returning set:
ret.set(indices[pick]);
//Then we replace it with the current (n-i)th element
//so that, when i is incremented, the
//first n-i elements are still available:
indices[pick] = indices[n-i-1];
}
return ret;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.