力扣每日一题0605-478. 在圆内随机生成点

154 阅读2分钟

给定圆的半径和圆心的位置,实现函数 randPoint ,在圆中产生均匀随机点。 持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

实现 Solution 类:

  • Solution(double radius, double x_center, double y_center) 用圆的半径 radius 和圆心的位置 (x_center, y_center) 初始化对象
  • randPoint() 返回圆内的一个随机点。圆周上的一点被认为在圆内。答案作为数组返回 [x, y] 。

示例 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]

拒绝采样

拒绝采样的意思是说:我们在一个更大的范围内生成随机数,并拒绝掉那些不在题目给定范围内的随机数,此时保留下来的随机数都是在范围内的。为了在一个半径为 R 的圆中生成均匀随机点,我们可以使用一个边长为 2R 的正方形覆盖住圆,并在正方形内生成均匀随机点,此时就只需要对于横坐标和纵坐标分别生成一个随机数即可。

由于正方形的面积为 (2R)2=4R2(2R)^2 = 4R^2,圆的面积为 πR2\pi R^2,因此在正方形中随机生成的点,落在圆内的概率为 Pr()=πR24R20.785\text{Pr}(\cdot) = \dfrac{\pi R^2}{4R^2} \approx 0.785,期望的生成次数为 E()=10.7851.274=O(1)\text{E}(\cdot) = \dfrac{1}{0.785} \approx 1.274 = O(1)

在正方形中生成点时(正方形中心的坐标简记为原点),如果我们在 [R,R)[-R, R) 的范围内生成随机数,那么是无法生成到横坐标或纵坐标恰好为 R 的点,对应到圆上时,会有圆周上与正方形边相切的两个点无法随机到。我们可以在生成时稍微提高右边界(例如 2R+ϵ2R + \epsilon,其中 ϵ\epsilon 是一个很小的常数,例如 10710^{-7},或者直接忽略这两个点,因为它们的勒贝格测度为零。

var Solution = function(radius, x_center, y_center) {
    this.xc = x_center;
    this.yc = y_center;
    this.r = radius;
};

Solution.prototype.randPoint = function() {
    while (true) {
        const x = Math.random() * (2 * this.r) - this.r;
        const y = Math.random() * (2 * this.r) - this.r;
        if (x * x + y * y <= this.r * this.r) {
            return [this.xc + x, this.yc + y];
        }
    }
};

复杂度分析

  • 时间复杂度:期望时间复杂度为 O(1)。
  • 空间复杂度:O(1)。