力扣中關於蓄水池抽樣問題官方標籤是 2 道,根據個人作題狀況來看,可能有三四道。比重算是比較低的,你們能夠根據本身的實際狀況選擇性掌握。node
蓄水池抽樣的算法思惟很巧妙,代碼簡單且容易理解,就算不掌握它,做爲了解也是很不錯的。算法
給出一個數據流,咱們須要在此數據流中隨機選取 k 個數。因爲這個數據流的長度很大,所以須要邊遍歷邊處理,而不能將其一次性所有加載到內存。數組
請寫出一個隨機選擇算法,使得數據流中全部數據被等機率選中。app
這種問題的表達形式有不少。好比讓你隨機從一個矩形中抽取 k 個點,隨機從一個單詞列表中抽取 k 個單詞等等,要求你等機率隨機抽取。無論描述怎麼變,其本質上都是同樣的。今天咱們就來看看如何作這種題。dom
這個算法叫蓄水池抽樣算法(reservoid sampling)。code
其基本思路是:索引
這種算法的核心在於先以某一種機率選取數,並在後續過程以另外一種機率換掉以前已經被選中的數。所以實際上每一個數被最終選中的機率都是被選中的機率 * 不被替換的機率。內存
僞代碼:leetcode
僞代碼參考的某一本算法書,並略有修改。
Init : a reservoir with the size: k for i= k+1 to N if(random(1, i) < k) { SWAP the Mth value and ith value }
這樣能夠保證被選擇的數是等機率的嗎?答案是確定的。get
所以對於前 k 個數,最終被選擇的機率都是 1 * 不被 k + 1 替換的機率 * 不被 k + 2 替換的機率 * ... 不被 n 替換的機率,即 1 * (1 - 被 k + 1 替換的機率) * (1 - 被 k + 2 替換的機率) * ... (1 - 被 n 替換的機率),即 $1 \times (1 - \frac{k}{k+1} \times \frac{1}{k}) \times (1 - \frac{k}{k+2} \times \frac{1}{k}) \times ... \times (1 - \frac{k}{n} \times \frac{1}{k}) = \frac{k}{n} $。
對於 第 i (i > k) 個數,最終被選擇的機率是 第 i 步被選中的機率 * 不被第 i + 1 步替換的機率 * ... * 不被第 n 步被替換的機率, 即 $\frac{k}{k+1} \times (1 - \frac{k}{k+2} \times \frac{1}{k}) \times ... \times (1 - \frac{k}{n} \times \frac{1}{k}) = \frac{k}{n} $。
總之,無論是哪一個數,被選中的機率都是 $\frac{k}{n}$,知足機率相等的需求。
蓄水池抽樣算法核心代碼很是簡單。可是卻不容易想到,尤爲是以前沒見過的狀況下。其核心點在於每一個數被最終選中的機率都是被選中的機率 * 不被替換的機率。因而咱們能夠採起某一種動態手段,使得每一輪都有機率選中和替換一些數字。 上面咱們有給出了機率相等的證實過程,你們不妨本身嘗試證實一下。以後結合文末的相關題目練習一下,效果會更好。