一、題目來源:
這個題目的由來是周圍有人討論到去面試(某8)的時候遇到了這個問題。另外正好HIT有個視頻也有這個內容,故記錄一下:
二、題目描述:
該人面試的時候問的是:
如何從二進制文件中等概率取整數?
這個題目說的有點不清楚實際上是:一個二進制文件中有好多好多整數,你要隨機取出一個。
三、題目分析
這個問題的難點就在於你開始不知道有多少的整數,也就是說這個(1/n)你不知道n是多少。
這里我們要用到蓄水池抽樣算法,這個算法的思想很簡單,我們待會再看,先看上面的題目。
四、題目解法
1)解法如下:
首先我們取到第一個數(暫時取的最后要不要還不一定呢),然后對第二個數以1/2的概率來確定是否 用第二個數來替換他, 然后對第二個數以1/3的概率來確定是否用第三個數來替換他。。。。一直這樣下去直到第n個數。經過上面的這個過程我們發現每個數取到的概率都變成了(1/n)。證明如下:![]()
總結起來就是一句話每個數取到的概率等於取到該數且取不到該數后面所有數的概率。如:取到第10個數的概率等於取到第十個數且取不到第11到第n個數的概率現在我們回到較復雜的情況,也就是如何在一個N個數(開始不知道N是幾)中隨機取M個數。其實思想是一樣的,就是先取出前M個,然后對后面的開始每個以(k/(i))的概率進行替換,這樣我們得到的就是所要的結果,證明如下:![]()
五、題目實現
OK!下面是python的代碼實現
-
1 import random 2 import copy 3 4 def reservoirSampling(seq, k): 5 localSeq = copy.deepcopy(seq) 6 N = len(localSeq) 7 for i in xrange(k, N): 8 M = int(random.uniform(0, i)) 9 if M < k : 10 temp = copy.deepcopy(localSeq[M]) 11 localSeq[M] = copy.deepcopy(localSeq[i]) 12 localSeq[i] = temp 13 return localSeq[0:k] 14 def main(): 15 a = [4,5,6,3,4,7,7,4,3,3,2,4,5,5,6,9,5,4,3,45,3,23,44,55,33,5,8] 16 k = 5 17 print reservoirSampling(a, k) 18 if __name__ == '__main__': 19 main()
六、總結歸納
怎么說呢,實在是太佩服這個想法了,好好學習領悟吧。