簡體   English   中英

從Java BitSet中隨機選取n個k位

[英]Randomly pick k bits out of n from a Java BitSet

如何從長度為mJava 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位置?

如果nk大得多,你可以在選擇盡可能多的算法之后減去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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM