题目描述

这是 LeetCode 上的 ​​478. 在圆内随机生成点 ,难度为 中等

Tag : 「数学」、「随机化」

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

实现 ​​Solution​​ 类:

  • ​Solution(double radius, double x_center, double y_center)​​​ 用圆的半径​​radius​​​ 和圆心的位置478. 在圆内随机生成点 : 圆内等概率随机采样_算法初始化对象
  • ​randPoint()​​​ 返回圆内的一个随机点。圆周上的一点被认为在圆内。答案作为数组返回478. 在圆内随机生成点 : 圆内等概率随机采样_段长度_02

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

提示:

  • 478. 在圆内随机生成点 : 圆内等概率随机采样_算法_03
  • 478. 在圆内随机生成点 : 圆内等概率随机采样_随机化_04
  • ​randPoint​​​ 最多被调用478. 在圆内随机生成点 : 圆内等概率随机采样_算法_05

等概率随机采样

为了方便,我们称圆心为 478. 在圆内随机生成点 : 圆内等概率随机采样_Java_06,半径为 478. 在圆内随机生成点 : 圆内等概率随机采样_Java_07

对给定圆内的点进行等概率随机采样,容易想到随机化两个信息:一个是距离圆心的距离 ​​len​​​(在范围 478. 在圆内随机生成点 : 圆内等概率随机采样_随机化_08 中进行随机),另外一个是夹角 ​​​ang​​​(在范围 478. 在圆内随机生成点 : 圆内等概率随机采样_算法_09 中随机,随便找个参考线即可,例如以往 478. 在圆内随机生成点 : 圆内等概率随机采样_Java_10 轴正方向的射线为参考)。

然后根据 ​​len​​​ 和 ​​ang​​ 直接计算对应的点的坐标,这样 可以确保随机出来的点一定在圆内,但并非「等概率」。

在不考虑夹角的情况下,我们本质是在 478. 在圆内随机生成点 : 圆内等概率随机采样_随机化_08 范围内随机,这在「一维」上「等概率」是成立的,因为满足「任意连续段中点被抽到的次数与总次数的比例」与「该连续段长度与总长度的比例」。

但在圆中并非如此,不考虑夹角时,「任意连续段 ​​len​​​ 与总长度 ​​r​​​ 的比例」和「​​len​​​ 对应面积与总面积比例」并不相等。例如 ​​len​​​ 有 478. 在圆内随机生成点 : 圆内等概率随机采样_随机化_12 的概率取到小于等于 478. 在圆内随机生成点 : 圆内等概率随机采样_后端_13 的值,而半径为 478. 在圆内随机生成点 : 圆内等概率随机采样_后端_13 扫过的面积仅为总面积的 478. 在圆内随机生成点 : 圆内等概率随机采样_段长度_15,因此我们的 ​​​len​​​ 不能直接在 478. 在圆内随机生成点 : 圆内等概率随机采样_随机化_08 范围内随机,为了消除这种一维转圆导致的「等概率」失效,我们可以从 478. 在圆内随机生成点 : 圆内等概率随机采样_Java_17 内随机再开平方,从而确保距离与面积比例一致。

代码:

class Solution {
double r, x, y;
Random random = new Random();
public Solution(double _r, double _x, double _y) {
r = _r; x = _x; y = _y;
}
public double[] randPoint() {
double len = Math.sqrt(random.nextDouble(r * r)), ang = random.nextDouble(2 * Math.PI);
double nx = x + len * Math.cos(ang), ny = y + len * Math.sin(ang);
return new double[]{nx, ny};
}
}
  • 时间复杂度:478. 在圆内随机生成点 : 圆内等概率随机采样_段长度_18
  • 空间复杂度:478. 在圆内随机生成点 : 圆内等概率随机采样_段长度_18

最后

这是我们「刷穿 LeetCode」系列文章的第 ​​No.478​​ 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour… 。

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。