在圆内随机生成点

224 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情

给定圆的半径和圆心的位置,实现函数 randPoint ,在圆中产生均匀随机点。

实现 Solution 类:

Solution(double radius, double x_center, double y_center) 用圆的半径 radius 和圆心的位置 (x_center, y_center) 初始化对象

示例 1:

输入: ["Solution","randPoint","randPoint","randPoint"] [[1.0, 0.0, 0.0], [], [], []]

输出: [null, [-0.02493, -0.38077], [0.82314, 0.38945], [0.36572, 0.17248]]

解释: Solution solution = new Solution(1.0, 0.0, 0.0);

solution.randPoint ();//返回[-0.02493,-0.38077]

solution.randPoint ();//返回[0.82314,0.38945]

solution.randPoint ();//返回[0.36572,0.17248]

提示:

0 < radius <= 108
-107 <= x_center, y_center <= 107
randPoint 最多被调用 3 * 104 次

思路和算法

对于半径为 radiusradius 的圆,考虑圆的外切正方形,其边长为 2×radius2×radius。为了在圆中产生均匀随机点,可以在圆的外切正方形中产生均匀随机点,使用拒绝采样算法产生圆中的随机点。

每次调用 randPointrandPoint 时,在圆的外切正方形中产生均匀随机点,如果产生的点在圆外则将产生的点拒绝并重新产生均匀随机点,直到产生的点在圆内。

实现方面,每次产生均匀随机点时计算产生的点与圆心的横坐标之差与纵坐标之差,并计算产生的点与圆心的距离,如果距离小于半径 radiusradius 则返回产生的点。

半径为 radiusradius 的圆的面积是 π×radius2π×radius2,其外切正方形的边长为 2×radius2×radius,面积为 4×radius24×radius2,因此在圆的外切正方形中产生的点位于圆中的概率是 π×radius24×radius2=π44×radius2π×radius2​=4π​,为了在圆中产生均匀随机点,在圆的外切正方形中产生均匀随机点的期望次数是 4π≈1.27π4​≈1.27。

代码

    double radius, xCenter, yCenter;
    Random random;

    public Solution(double radius, double x_center, double y_center) {
        this.radius = radius;
        this.xCenter = x_center;
        this.yCenter = y_center;
        this.random = new Random();
    }

    public double[] randPoint() {
        double x = 0, y = 0;
        boolean found = false;
        while (!found) {
            double xDelta = random.nextDouble() * 2 * radius - radius;
            double yDelta = random.nextDouble() * 2 * radius - radius;
            if (xDelta * xDelta + yDelta * yDelta <= radius * radius) {
                x = xCenter + xDelta;
                y = yCenter + yDelta;
                found = true;
            }
        }
        return new double[]{x, y};
    }
}