问题1:现在有一个文件行数未知,然后让你等概率的选择其中的一行,打印出来
你可能想着先遍历这个文件,统计行数n,然后对每个1/n的概率选择其中一行就可以了
可问题是,如果这个文件很大很大,或者这个文件一直处于动态的添加和删除状态,你无法静态的统计行数,该怎么办?
我们考虑用条件概率来做,首先以1/1的概率选择第一行,然后以1/2的概率选择第二行,以1/i的概率选择第i行,以此继续知道最后以1/n的概率选择最后一行。
让我们计算一下第一行最终被选择的概率P(1)=1/1*(1-1/2)*(1-1/3)...*(1-1/n)=1*1/2*2/3*...*(n-1)/n=1/n
第i行最终被选择的概率P(i)=1/i*(1-1/(i+1))*...*(1-1/n)=1/i*i/(i+1)*(n-1)/n=1/n
得解。
那么现在我们把上面的问题变一下看看有什么结果
问题2:现在有一个文件行数未知,以等概率选择其中的m行打印出来
继续用上面的方法?肯定不行!根本无法计算概率!
我们需要换种方法来解决。
让我们重新分析上面的问题,这次用不同的方法去做
我们维持一个变量max
对每一行产生一个[0,1]之间的概率,Pi
然后跟max比较,如果大于那么max重新赋值为Pi
一直到最后一行,然后我们输出max对应的那一行就可以了
是不是比上面的方法简洁多了,而且不需要那么多的乘法和除法(除法的时钟周期差不多比乘法高20倍)
正是这种转换给我们带来了思路,我们维持一个m大小的堆,来记录m个最大的概率就行了!