趣味题系列(5):

题目:给你一个长度为N的链表。N很大,但你不知道N有多大。你的任务是从这N个元素中随机取出k个元素。你只能遍历这个链表一次。你的算法必须保证取出的元素恰好有­k个,且它们是完全随机的(出现概率均等)。

 

解答:

题其实是编程珠玑习题12.10的推广,原题既是k=1的情况,关键就是想到可以替换以前已经选择的元素。
按照这个思路:
1. 对于前k个,全部选择,即选择集S里为前k个元素
2. 第k+i(i>0)个时,令r1=rand(1,k+i),如果r1>k,则保持现有的选择集合S不变
3. 如果r1<=k, 令r2=rand(1,k),并让第k+i元素(即当前元素)替换集合S里第r2个元素

归纳:
1. 如果N=k, 前k个全部选择,被选择概率p=1
2. 如果N=k+1, 第k+1个被选择的概率为p=k/(k+1),前k个被选择的概率为
p=1*(1/(k+1)+(k/(k+1))*((k-1)/k)) = k/(k+1)
3. 如果N=k+i,第k+i个被选择的概率为p=k/(k+i)=k/N,前k+i-1(N-1)个被选择的概率为
p=k/(k+i-1) * (i/(k+i) + (k/(k+i) * (k-1)/k) = k/(k+i-1) * (i/(k+i) +
(k-1)/(k+i)) =
k/(k+i-1) * (k+i-1)/(k+i) = k/(k+i) = k/N

你可能感兴趣的:(编程,算法,任务)