LeetCode探索(84):478-在圆内随机生成点

159 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

题目

给定圆的半径和圆心的位置,实现函数 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 <= 10^8
  • -10^7 <= x_center, y_center <= 10^7
  • randPoint 最多被调用 3 * 10^4

思考

本题难度中等。

首先是读懂题意。我们要在半径为radius、圆心位置(x_center, y_center)的圆中随机选择一个点。

我们可以使用拒绝采样的方法来解决这个问题。圆的半径为 R,那么我们可以使用一个边长为 2R 的正方形,在正方形内生成均匀随机点,也就是对于横坐标和纵坐标分别生成一个随机数即可。拒绝采样的意思是,如果生成的点落在圆内,我们就返回这个点,否则我们拒绝这个点,重新生成,直到新的随机点落在圆内。

点落在圆中的概率是 πR^2 / 4R^2 ≈ 0.785,因此期望的生成次数 ≈1.274,时间复杂度为 O(1)。

解答

方法一:拒绝采样

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

/**
 * @return {number[]}
 */
Solution.prototype.randPoint = function() {
  while (true) {
    // 在 [-R, R) 的范围内生成随机数
    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]
    }
  }
}

//  执行用时:136 ms, 在所有 JavaScript 提交中击败了67.11%的用户
//  内存消耗:57.1 MB, 在所有 JavaScript 提交中击败了69.74%的用户
//  通过测试用例:8 / 8

复杂度分析:

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

参考