持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
每日刷题 2022.06.11
- leetcode原题链接:leetcode.cn/problems/fi…
- 难度:中等
- 方法:随机函数、拒绝采样
题目
- 给定圆的半径和圆心的位置,实现函数 randPoint ,在圆中产生均匀随机点。
- 实现 Solution 类:
- Solution(double radius, double x_center, double y_center) 用圆的半径 radius 和圆心的位置 (x_center, y_center) 初始化对象
- randPoint() 返回圆内的一个随机点。圆周上的一点被认为在圆内。答案作为数组返回 [x, y] 。
示例
输入:
["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^7randPoint最多被调用3 * 10^4次
解题思路
相似的题目
- 黑名单中的随机数
- 也是同样的需要需要对于要求下的所有点都是同样的概率被取到,更巧妙的在于将符合要求的点放在一个连续的区间内,这样再使用随机函数,就可以使其都是相同的概率被取到。
重点
Math.random()函数的理解:Math.random() * ?乘以的这个数,扩大的是整个区间的长度,也就是右边界的值。而Math.random() + ?加上的这个数,是整体移动区间的左边界和右边界,区间的长度是不会改变的。- 也可以将乘法理解成:扩大区间的长度
- 加法理解成:整体移动区间
- 位移量的理解
分析题意
- 本题会给出半径和圆心的位置,需要我们在圆中随机的取点。
- 可以想到在这个圆的外面接一个正方形,也就是限制🚫
x、y的取值范围,然后再去判断当前获得的这个点是否在圆上。如果在圆上的话,就可以直接返回🔙。- 判断当前的点是否在圆上的办法:随机点到圆心的距离,是否小于等于半径。
- 两点之间的距离公式:
dir * dir = x * x + y * y
- 最后这种做法超时了。
优化
- 可以将区间计算出来,只将区间的长度固定下来,偏移量最后再添加上去。
- 也就是先计算出
x、y的裸值,再添加偏移量。- 裸值:计算范围大小
Math.random() * this.r * 2 - this.r - 偏移量:
x + this.xc, y + this.yc
- 裸值:计算范围大小
AC代码
/**
* @param {number} radius
* @param {number} x_center
* @param {number} y_center
*/
var Solution = function(radius, x_center, y_center) {
// 判断x的范围、y的范围
// 点到点之间的距离
this.r = radius;
this.xc = x_center;
this.yc = y_center;
// 查找个两个的范围,从圆心到四边封起来
this.r2 = this.r * this.r;
};
/**
* @return {number[]}
*/
Solution.prototype.randPoint = function() {
// 随机取一个,在正方型的范围内
// 因为是一个正方形,因此可能不在圆内
let flag = false, res = [];
// 固定的比较
while(!flag) {
// 判断是否在圆内
// res = this.rand();
// 计算距离
let x = Math.random() * this.r * 2 - this.r;
let y = Math.random() * this.r * 2 - this.r;
let dir = x * x + y * y;
if(dir <= this.r2) {
res = [x + this.xc, y + this.yc];
flag = true;
}
}
return res;
};
/**
* Your Solution object will be instantiated and called as such:
* var obj = new Solution(radius, x_center, y_center)
* var param_1 = obj.randPoint()
*/
总结
- 偏移的变量可以最后再添加上。