从n个数中生成m个不重复的随机数
import random
for i in range(n):
x = random.randint(n-i)
if x < m:
print(i)
m -= 1
由这个for循环循环n次,且在满足条件时才输出i,可知,输出m个不同值的要求已满足,因为每次输出的都是i值,而i值每次都是不一样的,m–保证了程序在输出了m个值后就停止循环。
在i=0时,randint()的取值范围为0到n-1,共n个数,此时要输出0只需要x小于m,故i=0被输出的概率为m/n;
在i=1时,randint()的取值范围为0到n-2,共n-1个数,若i=0没有被输出,则m–未被执行,此时i=1被输出的概率为m/(n-1),若i=0已经被输出了,则m变为m-1,此时i=1被输出的概率为(m-1)/(n-1);由概率论的知识,可知此时i=1被输出的概率为
P=(1-m/n)(m/(n-1))+m/n((m-1)/(n-1))=m/n;以此类推,可知每个数被输出的概率都为m/n
上题中如果n的大小不确定(可以认为是⼀个数据流),如何做?(蓄水池抽样算法)
int[] reservoir = new int[m];
// init
for (int i = 0; i < reservoir.length; i++)
{
reservoir[i] = dataStream[i];
}
for (int i = m; i < dataStream.length; i++)
{
// 随机获得一个[0, i]内的随机整数
int d = rand.nextInt(i + 1);
// 如果随机整数落在[0, m-1]范围内,则替换蓄水池中的元素
if (d < m)
{
reservoir[d] = dataStream[i];
}
}
- 整数数组的前m个直接存下来。
- 用一个计数器保存当前正在处理的请求是第几个,比如n
- 对于从m+1开始的新请求,以m/i的概率选择保存,并同从已保存的m个请求中随机选出的一个进行交换。
首先前m个数字是必须拿的。问题是当第i(i>m)个数字来的时候,究竟是要丢弃这个数,还是保留这个数?如果要保留这个数的话,则必须得丢弃手中已有的m个数,那是怎么确定丢弃哪个呢?
下面是就具体的做法。第i个数到来的时候,以m/i的概率决定是否要选择这个数字。如果选择了这个数字,则随机地替换掉手上m个数字中的一个。
如果前i-1个数字的时候保证了每个数字被选取的概率相等,则这样做之后可以保证每个数字被选取的概率也相等,为m/i。
- 第i个数选择的概率是m/i,因为算法就是这样决定的。
- 考虑前i-1个数字中的任意一个,它在第i个数之前被选择的概率是m/(i-1)。在第i个数字的时候,这个数字要被选择的话又两种可能,一是第i个数没有被选中(概率是1-m/i),二是第i个数倍选中了(概率是m/i)但是替换掉的数字不是它(概率是1-1/m),于是这个数在第i个数时仍然被选择的概率是m/(i-1) * ((1-m/i) + (m/i * (1-1/m))) = m / (i-1) * ((i-1) / i) = m/i。
由数学归纳法原理知,对于任意的n,当给完n个数的时候,选择的结果可以保证这n个数中每个被选中的概率都是相等
给你一个数组,设计一个既高效又公平的方法随机打乱这个数组
基本思想是每次随机从i到n中取一个数,然后把它交换到i的位置。
证明:一个元素m被放入第i个位置的概率P = 前i-1个位置选择元素时没有选中m的概率 * 第i个位置选中m的概率,即:
疯子坐飞机问题
转自
100人坐飞机,第一个乘客在座位中随便选一个坐下,第100人正确坐到自己坐位的概率是?
他们分别拿到了从1号到100号的座位,这些乘客会按号码顺序登机并应当对号入座,如果他们发现对应号座位被别人坐了,就会在剩下空的座位随便挑一个坐.现在假设1号乘客疯了(其他人没疯),他会在100个座位中随便选一个座位坐下,问:第100人正确坐到自己坐位的概率是多少?(也可推广到n名乘客n个座位的情况)
我们把这个问题叫做「疯子问题」。疯子问题是指:有 n 位乘客坐飞机,第一位乘客是疯子,会胡乱坐;后边的 n-1 位则按照自己的位置坐,如果被占就再随机选择另一个。求最后一个乘客坐对的概率。其中 n>1 。
我们看看疯子问题是如何转化的:
1.疯子坐对了
问题结束,所有人都可以坐对位置。
2.疯子坐错了,但并没有占据最后一个人的位置
假设疯子坐在了 k 号位置(1<k<n),那么从 2到 k-1 号都可以坐对位置,这个时候 k 号乘客进来了。他看到自己的位置被占了,于是重新选择一个位置就座。
注意!
也就是说,在这种情况下,除了 n 变小了,这个问题依然是一个疯子问题!只是 n 变成了 n-k+1 ,而这个第 k 号乘客就是新的「疯子」;而对于每一个疯子,他坐对的位置都是第一个疯子的那个位置。
3.疯子坐错了,而且坐在了最后一个人的位置上
问题结束,最后一个人不能坐在自己的位置上。
所以,第二个选项是无效的,它只是把问题中的n变小了,实质上等于没有做任何选择;且这个过程要么结束,要么会变成 n=2 的情况,这个情况下没有选项 2。
而只有 1 和 3 两个等概率的选项决定了最终结果,它们的概率分别为二分之一。
因此答案是二分之一。
——————————————————更深入的思考结果
其实这个问题还可以更简单。注意到在中间,如果任何一个随机选座位的人坐到了第一个疯子的位置,那么后边的所有人——当然包括最后一个人——就可以坐对。
因此最后一个人的位置只有两种可能:第一个疯子的,他自己的。
这两个位置又没有什么区别,也就是说在各种情况下都是对称的,所以它们的概率相等。
如果还是有问题,下边这个模型你一定能明白。
考虑一枚硬币,正面向上的概率为 1/n ,反面也是,立起来的概率为 (n-2)/n 。我们规定硬币立起来重新抛,但重新抛时,n会至少减小1。求结果为反面的概率。
这样很显然结果为 1/2 。而「正面向上」对应的是下一个疯子坐最后一个人的座位(选项 I);「反面向上」对应下一个疯子坐对的情况(选项 III );「立起来」则对应坐在中间的情况(选项 II)。
圆内接三角形是锐角三角形概率是多少
圆固定,分为上下两部;三角形固定底边和定点就确定了,底边落在水平直径上方和下方的概率均为1/2,顶点落在水平直径上下方的概率也是1/2,锐角三角形的条件是底边和顶点落在不同方,所以1/2*1/2为1/4。
一条长度为l的线段,随机在其上选2个点,将线段分为3段,问这3个子段能组成一个三角形的概率是多少
设随机选取的两个数为x,y,并令y>x,则把长度为1的线段截得的三段长度为x, y-x ,1-y,根据三角形两边和大于第三边以及两边之差小于第三边的定理,可以列出方程组 y>1-y; x<1-x; x+(1-y)>y-x; 即x<1/2; y>1/2; y>x+1/2;画图可以算得概率为1/8
三只骰子掷出10概率多少?
总情况:共有666=216种
结果分两类(1)三个骰子结果不同:1,3,6 ;1,4,5 ;2,3,5
共有33!=18种结果
(2)其中两个结果相同:2,2,6; 2,4,4; 3,3,4
共有33=9中结果
18+9=27
所以总概率为27/216=1/8=0.125
扔骰子,1-2对方赢,3-5 自己赢,6重新仍,问自己赢的概率
3/5
如何通过3L和5L的水构造N升的水?
N=4L的时候:将5L倒满,用5L往3L倒满(此时5L剩2L),将3L杯子水倒掉,将5L中剩余的2L水倒入3L中,将5L倒满(此时3L杯中有2L水),用5L向3L倒把3L倒满,5L杯子内的水就是4L。
如果一个人在公路上半小时遇到车的概率是0.9,那么10分钟之内遇到汽车的概率的是多少?
设答案为x,则(1-x)^3=1-0.9求出答案即为x
烧一根不均匀的绳,从头烧到尾总共需要1个小时。现在有若干条材质相同的绳子,问如何用烧绳的方法来计时一个小时十五分钟呢?
把第一根绳子两头同时点燃,同时把第二根绳子点燃一头,当第一根绳子烧完时,时间为半个小时,这时把第二根绳子的另一头也点燃,开始计时,当第二根绳子烧完时,停止计时,那么这段时间就是15分钟.
你有一桶果冻,其中有黄色、绿色、红色三种,闭上眼睛抓取同种颜色的两个。抓取多少个就可以确定你肯定有两个同一颜色的果冻?
四个。如果抓了3个,可能每个颜色各一个,当抓到第四个则一定会有两个小球颜色一致。
在半径为1的圆中随机选取一点。
在x轴[-1,1],y轴[-1,1]的正方形随机选取一点,如果此点在圆内,则即为所求的点。如果不在圆内,则重新随机直到选到了为止。
抛一个六面的色子,连续抛直到抛到6为止,问期望的抛的次数是多少。
方法一:因为每次抛到6的概率相等,都是1/6,于是期望的次数就是1/(1/6)=6次。
方法二:假设期望的次数为E。考虑第一次抛,如果已经抛到6了(概率为1/6),那么就不用再抛了。如果没抛到6(概率为5/6),那么还需要继续抛,可是还要抛多少次呢?显然,现在开始知道抛到6的次数仍然是E,但是刚刚已经抛了一次了于是可以得到这个等式
E = 1 * 1/6 + (1 + E) * 5/6,
解得 E = 6。即期望的次数为6次。
一个木桶里面有M个白球,每分钟从桶中随机取出一个球涂成红色(无论白或红都涂红)再放回,问将桶中球全部涂红的期望时间是多少?
令桶中有i个红球后再把全部球涂红的期望时间为a[i],此时再取出一个球,如果是红色的(概率为i/M),则直接放回,且剩余的期望时间仍是a[i]。如果是白色的(概率为1-i/M),则涂红后放回,剩余的期望时间为a[i+1],则
a[i] = (1 + a[i]) * i/M + (1 + a[i+1]) * (1 – i/M)
即 a[i] = a[i+1] + M/(M-i)
显然,有a[M] = 0
可以解得 a[0] = M/M + M/(M-1) + … + M/1 + 0
你有一把宝剑。每使用一个宝石,有50%的概率会成功让宝剑升一级,50%的概率会失败。如果宝剑的级数大于等于5的话,那么失败会使得宝剑降1级。如果宝剑的级数小于5的话,失败没有效果。问题是:期望用多少个宝石可以让一把1级的宝剑升到9级?
问题比较简单,用a[i]表示从第i-1级升到第i级期望使用的宝石数量。
当i<=5时,因为不会降级,则期望的数量均为2,即a[2] = a[3] = a[4] = a[5] = 2
当i>5时,因为会降级,成功时一个宝石就够了,不成功时需要倒退一级,需要先使用a[i-1]个宝石先回到i-1级,再使用a[i]个宝石升到第i级,即
a[i] = 1 * 1/2 + (1 + a[i-1] + a[i]) * 1/2
即 a[i] = a[i-1] + 2
可知,a[6]= 4, a[7] = 6, a[8] = 8, a[9] = 10
则1级到9级需要的宝石数为 a[2]+…+a[9] = 36。
已知有个rand7()的函数,返回1到7随机自然数,怎样利用这个rand7()构造rand10(),随机1~10。
产生随机数的主要原则是每个数出现的概率是相等的,如果可以得到一组等概率出现的数字,那么就可以从中找到映射为1~10的方法。
rand7()返回1~7的自然数,构造新的函数 (rand7()-1)*7 + rand7(),这个函数会随机产生1~49的自然数。原因是 1 49 1~49 1 49中的每个数只有唯一的第一个rand7()的值和第二个rand7()的值表示,于是它们出现的概率是相等。
但是这里的数字太多,可以丢弃