目录

LC 478. 在圆内随机生成点 (opens new window) (opens new window)

中等

# 问题描述

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

实现 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]

提示:

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

# 拒绝采样

这题容易陷入一个误区,随机生成一个 [r,r][-r,r] 范围内的随机数 xx,根据 xx 计算出可选的 yy 范围区间,再从区间中随机抽取 yy。实际上,如果按此方法生成随机点,随机点在圆上并非均匀分布的,而是两端密集,中间稀疏。下图是生成 2500025000 个随机点所得到的图像:

图像 1

原因在于,选取的 xx 是同概率的,但 xx 对应的 yy 的范围大小是不相同的,离圆心越远的 yy,可选的范围就越小,假设对应的 xx 坐标上有同样多的点存在(相当于 xx 随机),越远离圆心,yy可选的范围就越小,必然会往中间靠拢,就会形成上面两端密集,中间稀疏的图像,不满足均匀的条件。

因此,为了避免这种情况,就需要 yy 的可选范围不受 xx 取值影响,也就 xxyy 都从 [r,r][-r,r] 范围内生成,但这样有概率会落到圆外,处理方法是落到圆外重新生成一个新的坐标,直到生成的坐标落到圆内即可,落到圆内的概率为 P=πr24r20.785P = \dfrac {\pi r^2}{4r^2} \approx 0.785,生成坐标落到圆内的数学期望值为 E=10.7851.27E = \dfrac {1}{0.785} \approx 1.27 。如果在 [r,r][-r,r] 的范围内生成随机数,那么是无法生成到横坐标或纵坐标恰好为 rr 的点(随机函数区间是左闭右开),即圆周上与正方形边相切的两个点无法随机到,但实际上可以忽略不计。

按此方式生成 2500025000 个随机点所得到的图像如下:

图像 2

/**
 * @param {number} radius
 * @param {number} x_center
 * @param {number} y_center
 */
var Solution = function (radius, x_center, y_center) {
  this.r = radius
  this.x = x_center
  this.y = y_center
}

/**
 * @return {number[]}
 */
Solution.prototype.randPoint = function () {
  let r, x, y
  do {
    x = Math.random() * this.r * 2 - this.r
    y = Math.random() * this.r * 2 - this.r
    r = Math.sqrt(x * x + y * y)
  } while (r > this.r)
  return [x + this.x, y + this.y]
}

/**
 * Your Solution object will be instantiated and called as such:
 * var obj = new Solution(radius, x_center, y_center)
 * var param_1 = obj.randPoint()
 */
  • 时间复杂度:O(1)O(1)(期望)
  • 空间复杂度:O(1)O(1)
上次更新: 2023/01/31 19:48:05

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 , 转载请注明出处!