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};
    }
相关文章
相关标签/搜索