水塘抽樣(reservoir sampling)
題目:給出乙個資料流,這個資料流的長度很大或者未知。並且對該資料流中的資料只能訪問一次。請寫出乙個隨機選擇演算法,使得資料流中所有資料被選中的概率相等。
這個問題的擴充套件就是:如何從未知或者很大樣本空間隨機的取k個數?或者說,資料流長度為n行,要隨機抽取k行,則每一行被抽取的概率為k/n。
這個問題也就是在大資料流中的隨機抽樣問題:當記憶體無法載入全部資料時,如何從包含未知大小的資料流中隨機選取k個資料,並且要保證每個資料被抽取到的概率相等。
當k =1
k=1k=
1時首先考慮最簡單的情況,當k=1
k=1k=
1時,如何選取:
通過以上規律可以看出,對於k=1
k=1k=
1的情況,資料流中第i
個數被保留的概率為1
i\frac
i1。只要採取這種策略,只需要遍歷一遍資料流就可以得到取樣值,並且保證所有資料被選中的概率均為1
n\frac
n1。
當k
>
1k>1
k>1時
對於k
>
1k>1
k>
1的情況,我們可以採取類似的策略:
對於前k
個數,全部保留,對於第i(i>k)
個數,以k
i\frac
ik的概率保留第i
個數,並以1
k\frac
k1的概率與前面已選擇的k
個數中的任意乙個替換。
總結也就是說,在取第i
個資料的時候,生成乙個0
到1
的隨機數p
,如果p
p<\frac p,替換池中任意乙個為第 >ki p>\frac p>ik ,繼續保留前面的數。直到資料流結束,返回此 scala**實現i
個數;當pk
個數。但是為了保證計算準確性,一般是生成乙個0
到i
的隨機數,跟k
相比。import scala.util.random
/** * @author xiaoer
* @date 2020/1/11 23:53
*/object reservoirsampling
/*** 水塘抽樣演算法
** @param k 抽樣結果
* @param s 樣本總數
* @return k 樣本結果
*/def reservoirsampling(k: array[int], s: array[int]): array[int] =
// k+1 往後的資料
for (i <- k.length until s.length)
}// 返回值k}
}
Shuffle an Array 水塘抽樣
隨機性問題 水塘抽樣演算法可保證每個樣本被抽到的概率相等 使用場景 從包含n個專案的集合s中選取k個樣本,其中n為一很大或未知的數量,尤其適用於不能把所有n個專案都存放到主記憶體的情況 拿起第i張牌時,只從它前面的牌隨機選出j,或從它後面的牌隨機選出j交換即可 1 class solution 67...
水塘抽樣演算法
作用 水塘抽樣演算法是一種抽樣演算法,對於乙個很大的集合,抽取的樣本值能夠保證隨機.特點 其複雜度並不很高o n 並且能夠很大程度地節省記憶體.很多大公司的面試題都考察過這個演算法,以谷歌為例,有一道關於水塘抽樣的例題 我有乙個長度為n的鍊錶,n的值非常大,我不清楚n的確切值.我怎樣能寫乙個盡可能高...
leetcode 隨機概率 水塘抽樣
definition for singly linked list.struct listnode 水塘抽樣 維護乙個大小為1的水塘,由於確定head一定存在,定義res返回head val的值,然後讓head指向下乙個節點,同時定義乙個變數i,i初始化為2,當cur不為空的時候,迴圈在 0,i 1...