【LeetCode】均等概率問題,我有妙招!
在解決算法問題中我們會經常遇到要求均等概率的問題, 以leetcode 470. 用 Rand7() 實現 Rand10() 為例。
- 已有方法 rand7 可生成 1 到 7 范圍內的均勻隨機整數,試寫一個方法 rand10 生成 1 到 10 范圍內的均勻隨機整數。
- ⚠️ 不討論最優解,只討論算法思路 看到均等概率的問題, 我們最先要想到轉成2進制來處理,思路是讓均等概率轉換成均等概率出現0和1, 再由 0 和 1 ,增加位數來處理均等概率的其他數。拆解下上面的題目 我們使用 Rand7 轉成 Rand2 。讓 Rand2 的返回結果均等的出現 0 和 1, 我們可以用4位二進制數來生成包含 0 ~ 15 的數。舍棄 10~15,保留 0 到 9 ,結果加1 就是 1~ 10的隨機數。
第一步轉化二進制函數
Rand7() 的結果是均等概率 出現 1,2,3,4,5,6 拆解下就是 均等概率出現 1,2,3 和 4,5,6 當出現 1,2,3 的時候返回 0 ,當出現 4,5,6 的時候返回 1
- declare function rand7(): number
- function Rand2(): number {
- return Rand7() > 3 ? 1 : 0
- }
現在我們有了過渡函數 Rand2 , 那么我們使用隨機生成4位二進制數那么我就會得到 一個 均等生成 0 ~ 15 的函數
- function Rand15(): number {
- return Rand2() * 2 * 2 * 2 + Rand2() * 2 * 2 + Rand2() * 2 + Rand2()
- }
上面代碼略蠢,我們用移位的方法優化下, 左移操作符是二進制進位的。
- function Rand15(): number {
- return (rand2() << 3) + (rand2() << 2) + (rand2() << 1) + (rand2() << 0)
- }
那么最終的 Rand10() 函數, 我們只要舍棄掉 10~15 就可以了
- function Rand10(): number {
- let num: number
- // 使用do while 循環 遇到小于10 的結束循環返回結果,遇到大的繼續 roll
- do {
- num = Rand15()
- } while ( num > 9)
- return num + 1 // 別忘記 + 1
- }
這道題解決完了, 再來一道題,思路也是用二進制均等概率的。
- 給一個隨意函數f,以P概率返回 0 , 以 1-P 的概率返回1 這是你唯一可以使用的隨機機制,如何實現等概率返回 0 和 1
- 思路還是用二進制升位的方式, 0 的概率是 P 1 的概率是 1- P
可以得出 00 的概率是 P*P , 11 的概率是 (1-P) * (1-P) 01 的概率是 P * (1-P) 10 的概率是 (1-P) * P 而這兩個是相等的(交換率)
那么我們只要 保留 01 和 10 舍棄 00 和 11 就會獲得均等概率 P * (1-P)
10 和 01 這兩個數字不想等即可
- declare function f(): 0 | 1
- function round01 () : number {
- let num : number
- do {
- num = f()
- } while ( num == f())
- return num
- }
總結
兩道小題都是用二進制位來解決的算法題。解題思路也是兩個大致的方向,一個是把高進制的數拆解成均等的二進制均等概率,然后再組成目標數。另一個是通過升位來構造均等概率。