478.円の内側にランダムにポイントを生成する:円の内側に等しい確率のランダムサンプリング

創造を続け、成長を加速させましょう!「ナゲッツデイリーニュープラン・6月アップデートチャレンジ」に参加して12日目です。クリックしてイベントの詳細をご覧ください。

トピックの説明

これはLeetCodeでは478です。中程度の難易で円の中にランダムにポイントを生成します。

タグ:「数学」、「ランダム化」

randPoint円の半径と円の中心の位置を指定して、円内に均一なランダムポイントを生成する関数を実装します。

実装 Solution クラス:

  • Solution(double radius, double x_center, double y_center) 円の半径 radius と円の中心の位置を使用します (( バツ c n t r Y c n t r )。 (x_center、y_center) はオブジェクトを初期化します
  • randPoint() 円の内側のランダムな点を返します。円周上の点は円の内側にあると見なされます。回答は配列として返されます [[ バツ Y ] [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 <   r a d i u s < = 1 0 8 0<半径<=10^ 8
  • 1 0 7   < = x c e n t e r , y c e n t e r < = 1 0 7 -10^7 <= x_center, y_center <= 10^7
  • randPoint 最多被调用  3 × 1 0 4 3 \times 10^4  次

等概率随机采样

为了方便,我们称圆心为 ( x , y ) (x, y) ,半径为 r r

对给定圆内的点进行等概率随机采样,容易想到随机化两个信息:一个是距离圆心的距离 len(在范围 [ 0 , r ] [0, r] 中进行随机),另外一个是夹角 ang(在范围 [ 0 , 2 π ] [0, 2\pi] 中随机,随便找个参考线即可,例如以往 x x 轴正方向的射线为参考)。

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

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

但在圆中并非如此,不考虑夹角时,「任意连续段 len 与总长度 r 的比例」和「len 对应面积与总面积比例」并不相等。例如 len 1 2 \frac{1}{2} 的概率取到小于等于 r 2 \frac{r}{2} 的值,而半径为 r 2 \frac{r}{2} 扫过的面积仅为总面积的 1 4 \frac{1}{4} ,因此我们的 len 不能直接在 [ 0 , r ] [0, r] 范围内随机,为了消除这种一维转圆导致的「等概率」失效,我们可以从 [ 0 , r 2 ] [0, r^2] 内随机再开平方,从而确保距离与面积比例一致。

代码:

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};
    }
}
复制代码
  • 时间复杂度: O ( 1 ) O(1)
  • 空间复杂度: O ( 1 ) O(1)

最后

これは、「BrushthroughLeetCode」シリーズの最初のNo.478記事シリーズは2021/01/01に始まります。開始日現在、LeetCodeには1916の質問があり、その一部はロックされています。最初にすべての質問を入力します。ロックなし。トピックは終了しました。

このシリーズの記事では、問題解決のアイデアを説明することに加えて、可能な限り最も簡潔なコードを示します。一般的なソリューションが含まれる場合は、対応するコードテンプレートも提供されます。

学生がコンピューター上でコードをデバッグして送信できるようにするために、関連するリポジトリgithub.com/SharingSour…を確立しました。

倉庫の住所には、一連の記事の解決策へのリンク、一連の記事の対応するコード、LeetCodeの元の質問へのリンクおよびその他の推奨される解決策が表示されます。

おすすめ

転載: juejin.im/post/7105592091916386341