隨機——隨機取點

隨機取點

這兩天做了LeetCode上面關於Random的系列問題,雖然問題不多,但是能提供解決隨機問題的經典思路——按權重採樣和拒絕採樣。我們這裏只是討論關於隨機去點的基本問題,後面沒時間的話,可能不會深究。

Java Random API

首先,當然是最經典的Math.random(); 返回[0,1)的一個double值,區間內任意一個點被取到的概率都是等可能的。

double x = Math.random();
int i = (int)(Math.random() * 2); // 取0或者1,兩者是等可能的。
int j = (int)(Math.random() * 10); // {0, 1, 2, 3,...,9}是等可能的。

之後,是random.nextInt(int range); 返回{0, 1, ..., range-1}中任意一個數,每一個點被取到的概率是等可能的,也就是1/range。

Random rand = new Random();
int x = rand.nextInt(10); // 返回{0, 1, 2, ..., 9}中的任意數,每個數被取到的概率是1/10.

基本上,有這兩個API就足夠了。

按權重採樣

相關的經典題目是LeetCode的按權重採樣非重疊矩形中的隨機點。大概意思是,你現在有一個均勻分佈,如Math.random()或者nextInt,你需要把它按照權重分配一個數字出現的概率。比方說下面這幅圖,首先使用rand.nextInt(10)生成一個隨機數,再利用大小的比較返回不同的取值,這樣選到1的概率就是2/10, 2的概率是6/10,3的概率是2/10。

相關代碼如下,

public class MyRandom{
    Random rand = new Random();
    public int getInt() {
        int x = rand.nextInt(10);
        if (x >= 0 && x < 2) return 1;
        if (x >= 2 && x < 8) return 2;
        if (x >= 8 && x < 10) return 3;
    }
}

LeetCode裏面第528題,按照權重隨機取樣就是這個原理,但是不同的是,還需要結合二分查找法節省時間。

拒絕採樣

拒絕採樣的原理是非常簡單的,比方說,下面這個圖形,在整個正方形中隨機取點,如果點落在圓外,就拒絕這個點。那麼對於圓中各點來說,取到的概率是等可能的。給我們的思路是構造一個等可能的點序列,或者面,拒絕一些點就可以得到我們想要的概率。這樣講比較抽象,建議大家做一下這兩道題目: 用 Rand7() 實現 Rand10()在圓內隨機生成點。拒絕採樣是比較簡單通用的解法,所以我比較推薦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章