leetcode478. Generate Random Point in a Circle

題目要求

Given the radius and x-y positions of the center of a circle, write a function randPoint which generates a uniform random point in the circle.

Note:

1. input and output values are in floating-point.
2. radius and x-y position of the center of the circle is passed into the class constructor.
3. a point on the circumference of the circle is considered to be in the circle.
4. randPoint returns a size 2 array containing x-position and y-position of the random point, in that order.

Example 1:
Input: 
["Solution","randPoint","randPoint","randPoint"]
[[1,0,0],[],[],[]]
Output: [null,[-0.72939,-0.65505],[-0.78502,-0.28626],[-0.83119,-0.19803]]

Example 2:
Input: 
["Solution","randPoint","randPoint","randPoint"]
[[10,5,-7.5],[],[],[]]
Output: [null,[11.52438,-8.33273],[2.46992,-16.21705],[11.13430,-12.42337]]

Explanation of Input Syntax:

The input is two lists: the subroutines called and their arguments. Solution's constructor has three arguments, the radius, x-position of the center, and y-position of the center of the circle. randPoint has no arguments. Arguments are always wrapped with a list, even if there aren't any.

假設如今已知圓的圓心的x和y座標,以及該圓的半徑radius。要求寫一個隨機點生成器,要求該生成器生成的點必須在圓內,且每個點被生成的機率爲相等的。規定圓周上的點也屬於圓內。java

思路1:Rejection Sampling

該思路很簡單,即取可以容下該圓的最小正方形,而且隨機生成該正方形內的點。若是點不在圓內,則繼續從新生成。正方形內等機率的隨機點很好生成,能夠直接利用JAVA內置的隨機數生成器便可。x座標的隨機數範圍爲[x-radius, x+radius], y座標的隨機數範圍爲[y-radius, y+radius]。代碼以下:網絡

public double[] randPoint2() {
        double x0 = x_center - radius;
        double y0 = y_center - radius;
        while(true) {
            double xg = x0 + Math.random() * radius * 2;
            double yg = y0 + Math.random() * radius * 2;
            if (Math.pow((xg - x_center) , 2) + Math.pow((yg - y_center), 2) <= radius * radius)
                return new double[]{xg, yg};
        }
    }

思路二:極座標

假如咱們可以利用極座標的思想,先從(0, 360]度之間生成一個隨機的角度,再在[0, radius]之間生成一個隨機的長度,理論上就能夠了。可是經過這種方式生成的隨機點會明顯的在靠近圓心的位置密度更大,以下圖所示(圖片來源於網絡):app

clipboard.png

究其緣由在於,從圓心向圓周方向的半徑擴展出去,單位長度所構成的圓環的面積並不是相等的。以下圖(圖片來源於網絡):dom

clipboard.png

假設將圓周拆分爲等分的3部分,則最內圈的面積爲clipboard.png,中圈的面積爲clipboard.png=3A,同理外圈的面積爲5A。若是按照半徑上的每個點都是等機率生成的話,會發現內圈由於面積更小,致使點的密度更大。可是由此也能夠看出,第i圈的面積和單位面積成線性正相關。ide

clipboard.png

接着要先介紹兩個機率論中的概念:機率密度函數(probability density function 簡稱pdf)累計分佈函數(Cumulative Distribution Function 簡稱 cdf)函數

機率密度函數是指某個隨機數生成器生成的數字在某個點附近的機率值。好比如今有一個隨機數生成器可以等機率生成[a,b]區間的任意一個數,則其pdf(x)= 1/(b-a)spa

累計分佈函數對離散變量而言,全部小於等於a的值出現機率的和。仍是以[a,b]區間的等機率隨機數生成器爲例,cdf(x)表示隨機數生成器生成的數位於[a,x]區間內的機率,其值爲cdf(x)=(x-a)/(b-a) a<=x<=bcode

能夠看到cdf實際上是對pdf在該區間上進行微積分計算的結果。orm

從這題的角度而言,既然已知隨着r向着半徑增長,在該位置上生成隨機數的機率爲線性增長,所以能夠設clipboard.png,其中a爲機率值。由於已知生成的全部點的一定位於[0,R]之上,所以cdf(R)=clipboard.png,由此能夠得出clipboard.png。再將a的值帶回原式中,能夠得出clipboard.png。在對pdf(r)進行積分計算能夠得出clipboard.png。再次校驗能夠看到cdf(R)=1確實成立。blog

可是,JAVA只能提供一種通用的隨機數生成器,即在必定區間內每個數均爲等機率出現。對於這種隨機數生成器,其cdf(x)=x,即生成[0,x]之間的隨機數的機率爲r。將兩者相等便可得出以下結論clipboard.png

代碼以下:

public double[] randPoint() {
        double len= Math.sqrt(Math.random())*radius;
        double deg= Math.random()*2*Math.PI;
        double x= x_center+len*Math.cos(deg);
        double y= y_center+len*Math.sin(deg);
        return new double[]{x,y};
    }
相關文章
相關標籤/搜索