# 隨機取出其中之一元素
## 題目描述
一個文件中含有n個元素(n未知),要求在只能遍歷一遍這n個元素的情況下,等概率隨機的取出其中之一個元素。
## 分析與解法
假設5個人輪流抽簽,只有其中某一個人能中簽,那么,這5個人每個人中簽的概率是相等的。不信的話,咱們可以具體計算下。
首先,第一個人中簽的概率是1/5,第二個人中簽的情況只能在第一個人未中時才有可能,所以第二個人中簽的概率是4/5 X 1/4 = 1/5(4/5表示第一個人未中,1/4表示第二個人在剩下的4個簽里中簽的概率),所以,第二個人最終的中簽概率也是1/5,
同理,第三個人中簽的概率為:第一個人未中的概率 * 第二個人未中的概率 * 第三個人中的概率,即為:4/5 * 3/4 * 1/3 = 1/5,
一樣的可以求出第四和第五個人的概率都為1/5,也就是說先后抽簽順序不影響每個人中簽概率的大小。
回到咱們的問題,在明確了先后抽簽順序不影響不公平的原則之后,下面,給出選取策略:
順序遍歷,當前遍歷的元素為第L個元素,變量e表示之前選取了的某一個元素,此時生成一個隨機數r,如果r%L == 0(當然0也可以是0~L-1中的任何一個,概率都是一樣的), 我們將e的值替換為當前值,否則掃描下一個元素直到文件結束。
你要是給面試官說明了這樣一個策略后,面試官可能會問你這樣做是等概率嗎?那我們來證明一下。
在遍歷到第1個元素的時候,即L為1,那么r%L必然為0,所以e為第一個元素,p=100%。遍歷到第2個元素時,L為2,r%L==0的概率為1/2, 這個時候,第1個元素不被替換的概率為1*(1-1/2)=1/2,第1個元素被替換,也就是第2個元素被選中的概率為1/2,你可以看到,只有2時,這兩個元素是等概率的機會被選中的。
同理,當遍歷到第3個元素的時候,r%L==0的概率為1/3,前面被選中的元素不被替換的概率為1/2*(1-1/3)=1/3,前面被選中的元素被替換的概率,即第3個元素被選中的概率為1/3。
歸納法證明,這樣走到第L個元素時,這L個元素中任一被選中的概率都是1/L,那么走到L+1時,第L+1個元素選中的概率為1/(L+1), 之前選中的元素不被替換,即繼續被選中的概率為1/L*(1-1/(L+1)) = 1/(L+1)。證畢。
也就是說,走到文件最后,每一個元素最終被選出的概率為1/n, n為文件中元素的總數。
下面給出一個此選取策略的偽代碼:
```
Element RandomPick(file):
Int length = 1;
While (length <= file.size)
If (rand() % length == 0)
Picked = File[length];
Length++;
Return picked
```
## 舉一反三
一個文件含有n個元素, n未知的情況下, 順序遍歷一遍, 要求等概率隨機取r個,其中r < n。
- 程序員如何準備面試中的算法
- 第一部分 數據結構
- 第一章 字符串
- 1.0 本章導讀
- 1.1 旋轉字符串
- 1.2 字符串包含
- 1.3 字符串轉換成整數
- 1.4 回文判斷
- 1.5 最長回文子串
- 1.6 字符串的全排列
- 1.10 本章習題
- 第二章 數組
- 2.0 本章導讀
- 2.1 尋找最小的 k 個數
- 2.2 尋找和為定值的兩個數
- 2.3 尋找和為定值的多個數
- 2.4 最大連續子數組和
- 2.5 跳臺階
- 2.6 奇偶排序
- 2.7 荷蘭國旗
- 2.8 矩陣相乘
- 2.9 完美洗牌
- 2.15 本章習題
- 第三章 樹
- 3.0 本章導讀
- 3.1 紅黑樹
- 3.2 B樹
- 3.3 最近公共祖先LCA
- 3.10 本章習題
- 第二部分 算法心得
- 第四章 查找匹配
- 4.1 有序數組的查找
- 4.2 行列遞增矩陣的查找
- 4.3 出現次數超過一半的數字
- 第五章 動態規劃
- 5.0 本章導讀
- 5.1 最大連續乘積子串
- 5.2 字符串編輯距離
- 5.3 格子取數
- 5.4 交替字符串
- 5.10 本章習題
- 第三部分 綜合演練
- 第六章 海量數據處理
- 6.0 本章導讀
- 6.1 關聯式容器
- 6.2 分而治之
- 6.3 simhash算法
- 6.4 外排序
- 6.5 MapReduce
- 6.6 多層劃分
- 6.7 Bitmap
- 6.8 Bloom filter
- 6.9 Trie樹
- 6.10 數據庫
- 6.11 倒排索引
- 6.15 本章習題
- 第七章 機器學習
- 7.1 K 近鄰算法
- 7.2 支持向量機
- 附錄 更多題型
- 附錄A 語言基礎
- 附錄B 概率統計
- 附錄C 智力邏輯
- 附錄D 系統設計
- 附錄E 操作系統
- 附錄F 網絡協議
- sift算法
- sift算法的編譯與實現
- 教你一步一步用c語言實現sift算法、上
- 教你一步一步用c語言實現sift算法、下
- 其它
- 40億個數中快速查找
- hash表算法
- 一致性哈希算法
- 倒排索引關鍵詞不重復Hash編碼
- 傅里葉變換算法、上
- 傅里葉變換算法、下
- 后綴樹
- 基于給定的文檔生成倒排索引的編碼與實踐
- 搜索關鍵詞智能提示suggestion
- 最小操作數
- 最短摘要的生成
- 最長公共子序列
- 木塊砌墻原稿
- 附近地點搜索
- 隨機取出其中之一元素