刚刷到这个帖,我第一反应就是,互联网这行真能把人拧巴坏。40+,以前P8年薪130万,歇了快两年,现在再回来拿70万offer,还在纠结接不接,外人一看可能会说这还犹豫啥,我倒觉得太正常了。
人不是只看绝对数字的,之前站过高处,再往下走,心里那个坎真不是一句“先上车再说”能过去的。更别说40+这个节点,本来就敏感,接了怕以后封顶,不接又怕市场继续往下掉,左右都别扭。
最扎心的是,很多人看到的是70万,只有当事人脑子里循环播放的是“我是不是回不去了”。这玩意儿吧,钱是钱,落差也是实打实的。
今日算法题
半夜写压测脚本的时候,这种题我一般不信“看起来对”的写法。 很多人上来就是先在 ([-r,r]) 里随便取个 x 、 y ,然后直接塞进结果集。代码能跑,分布一点都不均匀。圆心附近和边缘附近的密度,肉眼一看就不对。
这题麻烦不在“生成随机数”,麻烦在“生成得像回事”。
先说最容易写、也最稳的一种:拒绝采样。 做法很直,先在外接正方形里随机打点,也就是 x 、 y 都落在 [-r, r] 之间。再判断这个点是不是在圆内,只要满足 x*x + y*y <= r*r ,就收下;不满足就丢掉重来。
这种写法的好处是不用跟三角函数较劲,也不容易把概率分布写歪。
import java.util.concurrent.ThreadLocalRandom;
publicclassCirclePointGenerator{
publicstaticdouble randomPoint(double radius) {
ThreadLocalRandom random = ThreadLocalRandom.current;
while (true) {
double x = random.nextDouble(-radius, radius);
double y = random.nextDouble(-radius, radius);
if (x * x + y * y <= radius * radius) {
returnnewdouble{x, y};
}
}
}publicstaticvoidmain(String[] args){
double point = randomPoint(10.0);
System.out.println("x=" + point[0] + ", y=" + point[1]);
}
}
这段代码看着土一点,但现场里我反而更愿意先写这个。原因很简单:不容易错。
有些同学会换一种思路,先随机角度,再随机半径:
double angle = random.nextDouble(0, 2 * Math.PI);
double len = random.nextDouble(0, radius);
double x = len * Math.cos(angle);
double y = len * Math.sin(angle);
这段代码最大的问题是: len 如果直接均匀随机,点会偏向圆心。 为什么?因为圆越往外,环带面积越大。你半径按线性均匀取,等于把小圆和大圆给了差不多的概率,这分布肯定不对。
要修正也不复杂,半径不能直接取,得开方:
import java.util.concurrent.ThreadLocalRandom;
publicclassCirclePointGenerator2{publicstaticdouble randomPoint(double radius) {
ThreadLocalRandom random = ThreadLocalRandom.current;
double angle = random.nextDouble(0, 2 * Math.PI);
double len = Math.sqrt(random.nextDouble) * radius;
double x = len * Math.cos(angle);
double y = len * Math.sin(angle);
returnnewdouble{x, y};
}
}
这里的关键就一行:
double len = Math.sqrt(random.nextDouble) * radius;
别小看这个 sqrt ,少了它,分布基本就废了。
所以这题真要我在面试里写,我通常看场景选方案。 要的是稳、快、不容易翻车,我写拒绝采样。 要的是体现你真懂概率分布,我会补一句极坐标解法,并点明半径为什么要开方。
热门跟贴