随机数发生器。
给定一个随机数发生器构造另一个随机数发生器;
给定一个随机数发生器对数列进行采样。
- 给定一个等概率随机产生1~5的随机函数f()。除此之外,不能使用任何额外的随机机制,请实现等概率随机产生1 ~ 7的随机函数。
解答:将f()通过乘和加的运算构造自然数序列。
步骤1 g() = f()-1 -> 0,1,2,3,4
步骤2 g()*5 + g() -> 0,1,2,3,4,5,6,7,…,24
步骤3 若步骤2产生的数大于20,重复步骤2;若小于等于20,%7,即可等概率产生0-6
步骤4 步骤3结果+1.
def randomInt5():
# 生成1-5的随机函数
return int(random.random()*5) + 1
def randomInt7():
res = (randomInt5()-1)*5 + (randomInt5()-1) #0,1,2,..,24
if res <= 20:
return res % 7
else:
return randomInt7()
if __name__ == "__main__":
dic = {}
for i in range(100000):
res = randomInt7()
if res not in dic:
dic[res] = 1
else:
dic[res] += 1
print(dic)
- 给定一个以p概率生成0,以1-p概率产生1的随机函数f(),p是固定的值,但是你并不知道是多少。除此之外也不能使用任何额外的随机机制,请用f()实现等概率随机产生0和1的随机函数。
解答:虽然p未知,但是连续调用f()2次,产生01和10序列的概率均为p(1-p)。基于这点可以等概率随机产生0和1。
import random
def f(p:float=0.3):
# 以p的概率产生0,以1-p的概率产生1
if random.random()<p:
return 0
else:
return 1
def generate(p:float=0.3):
first = f(p)
second = f(p)
if first==0 and second==1:
return 0
elif first==1 and second==0:
return 1
else:
return generate(p)
if __name__ == "__main__":
cnt = 0
for i in range(500000):
if generate()==1:
cnt += 1
print(cnt)
3 假设函数f()等概率随机返回一个在[0,1)范围上的浮点数,那么我们知道,在[0,x)区间上的数出现的概率为x(0<x<=1)。给定一个大于0的整数k,并且可以使用f()函数,请实现一个函数依然返回在[0,1)范围上的数,但是在[0,x)区间上的数出现的概率为x的k次方。
解答:调用K次f(),返回较大的数即可。
def randomK(k:int=3):
max_value = -1
for i in range(k):
tmp = random.random()
max_value = max(max_value, tmp)
return max_value
if __name__ == '__main__':
for i in range(100):
print(randomK())
- 给定一个长度为 N 且没有重复元素的数组 arr 和一个整数 M,实现函数等概率随机打印 arr 中的 M 个数。
解答:有很多思路去实现题中的"随机",这里介绍一种代价较低的方案。
步骤1:在0-N-1中随机得到一个index,将index的值输出,并与数组最后一个位置交换
步骤2:在0-N-2中随机得到一个index,将index的值输出,并与数组倒数第二个位置交换。
如此操作,直到输出M个数。
def selectM(arr, m:int=5):
n = len(arr)
for i in range(m):
idx = int(random.random() * (n-i)) - 1
print(arr[idx])
arr[idx], arr[n-i-1] = arr[n-i-1], arr[idx]
if __name__ == '__main__':
arr = [1,2,3,4,5,6,7,8,9,10]
selectM(arr)
print(arr)
- 有一个机器按自然数序列的方式吐出球,1号球,2号球,3号球等等。你有一个袋子,袋子里最多只能装下K个球,并且除袋子以外,你没有更多的空间,一个球一旦扔掉,就再也不可拿回。设计一种选择方式,使得当机器吐出第N号球的时候,你袋子中的球数是K个,同时可以保证从1号球到N号球中的每一个,被选进袋子的概率都是K/N。
更具体的例子:
有一个只能装下10个球的袋子,当吐出100个球时,袋子里有10 球,并且1 ~ 100号中的每一个球被选中的概率都是10/100。
然后继续吐球,当吐出1000个球时,袋子里有 10 个球,并且1 ~ 1000号中的每一个球被选中的概率都是10/1000。
继续吐球,当吐出i个球时,袋子里有10个球,并且1 ~ i号中的每一个球被选中的概率都是10/i。也就是随着N的变化,1~N号球被选中的概率动态变化成k/N。
解答:蓄水池抽样算法
基本过程:
步骤1)处理1-K号球时,直接放进袋子里;
步骤2)处理第 i 号球时,以 k/i 的概率决定是否将第 i 号球放进袋子里。如果不决定将第 i 号球放进袋子,直接扔掉第 i 号球;如果决定将第 i 号球放进袋子,
那么就从袋子里的 k 个球中随机扔掉一个,然后把第 i 号球放入袋子。
步骤3)处理第 i+1 号球时, 重复步骤1或步骤2。
证明:
情形一) 假设第 i 号球被选中,并且 1 <= i <= k,那么第 i 号球最终留在袋子中的概率是 K/N。
在选 k+1 号球之前,第i号球留在袋子中的概率为1。
在选 k+1号球时,只有决定将k+1号球放入袋子,同时在袋子中的第i号球被随机选中并决定扔掉,这两个事件同时发生时第i号球才会被淘汰,第i号球被淘汰的概率是 k k + 1 × 1 k = 1 k + 1 \frac{k}{k+1} \times \frac{1}{k} = \frac{1}{k+1} k+1k×k1=k+11,所以第i号球留下来的概率是是 k k + 1 \frac{k}{k+1} k+1k;
在选 k+2 号球时,只有决定将 k+2 号球放入袋子,同时在袋子中的第i号球被随机选中并决定扔掉,这两个事件同时发生时第i号球才会被淘汰,第i号球被淘汰的概率是 k k + 2 × 1 k = 1 k + 2 \frac{k}{k+2}\times\frac{1}{k}=\frac{1}{k+2} k+2k×k1=k+21,所以第i号球留下的概率是 k + 1 k + 2 \frac{k+1}{k+2} k+2k+1
依次类推,在选N号球时,从1号到N号的全部过程中,第i号球最终留在袋子中的概率是
k k + 1 × k + 1 k + 2 ∗ k + 2 k + 3 ∗ k + 3 k + 4 . . . . ∗ N − 1 N = k N \frac{k}{k+1}\times\frac{k+1}{k+2}∗\frac{k+2}{k+3}∗\frac{k+3}{k+4}....∗\frac{N−1}{N}=\frac{k}{N} k+1k×k+2k+1∗k+3k+2∗k+4k+3....∗NN−1=Nk
情形二) 假设第i号球被选中,并且 k < i <= N。那么第 i 号球最终留在袋子中的概率是 K/N。
第 i 号球被选中留下的概率是 k i \frac{k}{i} ik。
第 i+1 号球被选中,并且i号球淘汰的概率是 k i + 1 ∗ 1 k = 1 i + 1 \frac{k}{i+1} * \frac{1}{k} = \frac{1}{i+1} i+1k∗k1=i+11, 第 i 号球留下的概率是 i i + 1 \frac{i}{i+1} i+1i。
依次类推,在选N号球时,第i号球最终留在袋子中的概率是:
k i ∗ i i + 1 ∗ i + 1 i + 2 . . . ∗ N − 1 N = k N \frac{k}{i} * \frac{i}{i+1} * \frac{i+1}{i+2}... * \frac{N-1}{N} = \frac{k}{N} ik∗i+1i∗i+2i+1...∗NN−1=Nk
基本概率题
- 三只蚂蚁从正三角形的三个定点沿着边移动,速度是相同的,它们碰头的概率是多少?
解答:只要两个碰头就算碰头。答案是 3 4 \frac{3}{4} 43 - 假设某地区重男轻女,一个家庭如果生出一个女孩就一直生,知道生出男孩就停止生育。假设一胎只出生一个孩子,问时间足够长后,男女比例是会变为多少?
解答:1:1 - 8只球队,3个强队,其余都是弱队。随机把它们分成4组比赛,每组两个队。问两强相遇的概率是多大?
解答:
8只球队的分组数:
f ( 8 ) = C 8 2 ∗ C 6 2 ∗ C 4 2 ∗ C 2 2 4 ∗ 3 ∗ 2 ∗ 1 f(8) = \frac{C_{8}^{2}*C_{6}^{2}*C_{4}^{2}*C_{2}^{2}}{4*3*2*1} f(8)=4∗3∗2∗1C82∗C62∗C42∗C22
8只球队中,让3个强队中两强一组的分组数: C 3 2 C_{3}^2 C32,其他6队随机分组:
f ( 6 ) = C 6 2 ∗ C 4 2 ∗ C 2 2 3 ∗ 2 ∗ 1 f(6) = \frac{C_{6}^{2}*C_{4}^{2}*C_{2}^{2}}{3*2*1} f(6)=3∗2∗1C62∗C42∗C22
8只球队中,两强相遇概率:
f ( 6 ) ∗ C 3 2 f ( 8 ) = 3 7 \frac{f(6)*C_{3}^2}{f(8)} = \frac{3}{7} f(8)f(6)∗C32=73
注:不能直接 C 8 2 ∗ C 6 2 ∗ C 4 2 ∗ C 2 2 C_{8}^{2}*C_{6}^{2}*C_{4}^{2}*C_{2}^{2} C82∗C62∗C42∗C22计算分组数的原因是会将分组重复计算。
参考:
链接1
链接2