问题如上。
这是我被面试的一个题目。我的第一反应给出的解决办法是,开启 n 个线程并标记序号,各个线程打印出它的序号。直到有 m 个线程被调度时,停止所有线程。
打印出的序号即是 m 个等概率出现的数字。
面试官听到这个解决办法,吸了一口凉气,估计心里在想,这小伙疯了!我当时自知这个解决方案不是面试官想要的,于是说了,如果这个 n 很大,那么就要另
想办法了,因为不可能在一个进程里产生任意多个线程。
想啊想,过了两分钟,还是没有找到解决办法。面试官很 nice 让我回去后再想一想。
其实这个题细想,有些难度。你可能有一种思路:如果能一次性取出 m 个数字,再保证各数字是随机的,则可以满足等概率。但。。。如何一次性取出 m 个数字呢?
一次性生成多个随机数?如果生成的数字有相同则不是等概率的,因为这个数字比其它的数字出现的次数多,则概率大些(尽管你忽略了它出现多次)。或者还有思路:
每次出一个,保证取 m 次得到的各数字概率相等。听起来,似乎这种思路要难些。
[解法一]
我们来模拟这个过程,设有一个长度为 m 的辅助数组 B,用来装选中的数字。数组末满时,依次从长度为 n 的数组 A 中每次取一个数字顺序放入 B 中。直到 B 满了。
设对于后续的每一个元素,其装入 B 中的概率为 x。此元素装入 B 中的操作是将它与 B 中的某个元素置换。
则 B 中已经存在的某个元素,继续在 B 中存在的概率为:(1-x) + x*(m-1)/m,即当前取出的元素不进入 B,被直接舍弃