参考文章:http://www.cnblogs.com/ywl925/p/3793003.html
问题定义:
给你一个长度为N的链表。N很大,但你不知道N有多大。你的任务是从这N个元素中随机取出k个元素。你只能遍历这个链表一次。你的算法必须保证取出的元素恰好有k个,且它们是完全随机的(出现概率均等)。
求解:
蓄水池算法:
蓄水池算法是针对从一个序列中随机抽取不重复的K个数,保证每个数被抽取到的概率都为K/N这个问题构建的
做法:
首先构造一个可以容纳k个元素的蓄水池,将序列前k个元素直接放入蓄水池中
然后从第k+1个数据开始,以k/i(k<i=n)的概率来决定它是否进入蓄水池。
当遍历完N个数据,蓄水池中所剩的K个元素就是就是挑选出的元素
时间复杂度为O(N)
证明每个数被抽取到的概率都为K/N
对于第i个数(i<k),在前k步被选中的概率都是1,从第K+1步开始,每一步i不被选中的概率为依次为k/k+1,k+1/k+2...,那么读到第n个数时,就可以算出第i个数(i<k)被选中的概率=被选中的概率*以后每一步都不被换走的概率
即 1*(k/k+1)*(k+1/k+2)*...*(n-1/n) = k/n
对于第j个数(j>=k)被选中的概率为:在他出现时被选中的概率*在他出现后不被换走的概率,
即(k/j)*(j/j+1)*(j+1/j+2)*...*(n-1/n) = k/n
综上得证
关于蓄水池算法的几个文章:
蓄水池算法介绍和证明【原创】:http://www.cnblogs.com/aboutblank/p/4800874.html
算法【34】蓄水池抽样算法:https://www.cnblogs.com/python27/p/Reservoir_Sampling_Algorithm.html