蓄水池抽樣算法

什麼是蓄水池抽樣,它能解決什麼問題?html

從一次面試提及

百度面試以算法爲主啊,手動寫代碼。第一道題是實現c語言庫函數strcpy,這個原理很簡單,但要注意如下這幾點:java

  • 空指針檢查(包括src和dest)
  • 內存重疊,要檢查指針是否重疊
  • 最後拷貝時,別忘了在dest追加字符串終結符號0
  • 如何保證dest已分配足夠內存
  • 爲何從後往前拷貝?

第二道題是寫一個java類,實現堆的操做。說實話,雖然堆的操做不難,但要真正實現它並不容易。如下須要注意的點:python

  • 泛型參數(泛化編程)
  • 類型必需可比較或者提供比較器
  • 不能實例泛型類型,即不能new T[]或者new T(),只能使用Object數組
  • 內存動態分配,內存拷貝(數組拷貝)

重點是第三道題目:給定一個文件,從中隨機取出n行,並計算時間複雜度。我上來即是這樣的代碼:面試

import random
def sample(filename, n = 3):
    assert(filename is not None)
    result = []
    with open(filename) as f:
        lines = f.readlines()
    while len(result) < n :
        line = random.choice(lines)
        if line not in result:
            result.append(line.strip())
    return result

這種方法算法

  • 必須把文件內容全讀入內存,若是文件很大怎麼辦?
  • 設N爲文件行數,n和N接近時,越到後面,衝突越大,效率極低。
  • 有人說,先隨機生成n個數構成一個集合A(仍是有衝突哦),讀取文件,當行數屬於A時,取出該行,問題不就解決了?
    問題是文件總行數是多少?必須知道文件總行數才能知道隨機數的取值範圍啊。必須先掃描一遍文件?文件很大時這樣的效率如何?

後來面試官問我知不知道分治法,我說了解,但這有關係麼?編程

蓄水池抽樣

蓄水池抽樣(Reservoir Sampling )是一個頗有趣的問題,它可以在o(n)時間內對n個數據進行等機率隨機抽取,
例如:從1000個數據中等機率隨機抽取出100個。另外,若是數據集合的量特別大或者還在增加(至關於未知數據集合總量),
該算法依然能夠等機率抽樣。數組

以上摘自handspeaker博客app

算法步驟爲:dom

  1. 從文件中取前n行,結果集result
  2. 令i表示當前行數,c爲當前行內容,m = random(1, i),即m爲1~i的一個隨機數。
  3. 若m <= n, 則令result[m] = c,即替換第m行內容,不然捨棄c。
  4. 若已到文件結尾,退出算法,返回result,不然轉2

利用概括法能夠證實每行被取的機率是相等的,證實過程
handspeaker博客函數

回到問題

問題解決了,毫無懸念!

import random
def sample(filename, n = 5):
    assert(filename is not None)
    result = []
    with open(filename, mode = "r") as f:
        for i in range(n):
            line = f.readline()
            if line == '':
                return result
            else:
                result.append(line.strip())
        i = n
        for line in f:
            k = random.randint(0, i)
            if k < n:
                result[k] = line.strip()
            i += 1
    return result
相關文章
相關標籤/搜索