【转载】随机生成k个范围为1-n的随机数,其中有多少个不同的随机数?

来源:http://www.cnblogs.com/haolujun/archive/2012/11/11/2765102.html

假如现在让你随机生成k个范围在1-n内的随机数,那么你能得到多少个不同的随机数呢?刚开始想得时候,我认为当k<=n时,可以得到k个不同的随机数,但是显然这个想法错了。做了个实验在1-1024内随机生成500个数,其中只有394个不同的数,随机生成1000个数,其中有639个不同的数。

接下来是很枯燥的数学推导,如果你只是想看看最后的公式,那么就看倒数第二行。如果你想看看推导过程那么就看下去。下面说的东西用到了概率和组合数学中的线性常系数非齐次递推关系。

现在我们想求一下,随机生成k个范围在1-n内的随机数,能得到多少个不同的随机数。

设我们随机k次得到的的k个数字为x1,x2,......xk。

设E[i]为随机i次得到的不重复数字个数的期望。

设p[i]为第i次随机得到的xi与x1,x2,......,x[i-1]其中一个重复的概率。

设q[i]为第i次随机得到的xi与x1,x2,......,x[i-1]中任何一个都不重复的概率。

那么显然p[i]=E[i-1]/n ,qi=(n-E[i-1])/n。

设Yi为指示器变量,Yi=1代表xi与x1,x2,......,x[i-1]中任何一个都不重复,Yi=0代表xi与x1,x2,......,x[i-1]其中一个重复。

那么由E[i]的意义可得E[i]=sigma(1*q[j])+sigma(0*p[j])=sigma(1*q[j])=sigma((n-E[j])/n) {0<=j<=i-1}。

现在可以得到E[i]=i-(1/n)*sigma(E[j]) {0<=j<=i-1}。现在我们就得到了一个递推关系式,并且我们知道E[0]=0,E[1]=1,我们可以用这个递推关系式求E[i]。

当然我们并不仅仅止于此,我们继续研究这个递推关系式,求出一个通项公式来。

E[1]=1
E[2]=2-1/n * E[1]
E[3]=3-1/n * (E[1]+E[2])
E[4]=4-1/n * (E[1]+E[2]+E[3])
...
E[k]=k-1/n * (E[1]+E[2]+E[3]+......+E[k-1])

我们把用下面的式子减去上面的式子得到:

E[2]-E[1]=1-1/n * E[1]
E[3]-E[2]=1-1/n * E[2]
E[4]-E[3]=1-1/n * E[3]
...
E[k]-E[k-1]=1-(1/n)*E[k-1]

现在设S[i]=E[1]+E[2]+......+E[i],我们得到如下递推式:S[k]-S[1]-S[k-1]=k-1-(1/n)*S[k-1]。

由于S[1]=1,我们得到:S[k]-(n-1)/n * S[k-1]= k。这是一个线性常系数非齐次递推关系,对于这种递推关系求通项公式,组合数学上说的很详细。

通过解这个递推关系,我们求得通项公式为S[k]=(1-2*n+n*n)*((n-1)/n)^(k-1)+(1-n)*n+n*k。

把S[k-1]带入E[k]中得:  E[k]=k-(1/n)*((1-2*n+n*n)*((n-1)/n)^(k-2)+(1-n)*n+n*(k-1))

当k趋向正无穷时,E[k]=k-(1/n)*(0+(1-n)*n+n*(k-1))=n,与我们的直觉是相符的。

现在,如果想得到n个不同的数,那么k应该大概是多少呢?

我们假设一系列的试验,C1,C2,C3,......,Ck中,Ci代表第i次试验随机生成的数字。

那么我们可以对试验进行阶段划分,阶段i为:第i次试验成功后的试验开始,第i+1次试验成功结束。阶段i的试验次数为X[i].

那么总的试验次数X=X[0] + X[1] + .... + X[n-1]。

第i个阶段的每次试验成功的概率为p=(n-i)/n,这是一个几何分布,也就是说第i个阶段的试验次数的期望为1/p= n/(n-i)。

那么总的试验次数期望为:X= n/(n-0) + n/(n-1) + n/(n-2) + ...... + n/1 = n*(1 + 1/2 + 1/3 + ...... + 1/n) = n * Hn

其中Hn=(1 + 1/2 + 1/3 + ...... + 1/n) ~ log(n)。所以,可以如果要生成n个不同的数,那么大概需要的试验次数是nlogn级别的。

时间: 2024-08-25 05:00:48

【转载】随机生成k个范围为1-n的随机数,其中有多少个不同的随机数?的相关文章

JavaScript随机生成颜色的方法

JavaScript随机生成颜色的方法 这篇文章主要介绍了JavaScript随机生成颜色的方法的相关资料,非常不错,代码简单易懂,具有参考借鉴价值,需要的朋友可以参考下 废话不多说了直接给大家贴js代码了,具体代码如下所述: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <!DOCTYPE html> <html>

随机生成四位验证码

namespace 随机生成验证码{    class Program    {        static void Main(string[] args)        {            while (true)            {                string s = "abcdefghijklmnopqrstuvwxyz";                string t = "李青用强力的回旋踢击退地方英雄,对目标以及被目标撞到的任何敌人

随机生成数字验证码

protected void Page_Load(object sender, EventArgs e) { // 生成验证码 string checkCode = RandLetter(4); // 把新的验证码保存到Session中 Session["CheckCode"] = checkCode; // 输入验证码 CreateImages(checkCode); } /// <summary> /// 生成验证图片 /// </summary> ///

Excel随机生成数据2

200万耗时大约 10秒以内,输出结果到txt文件. Sub GetPassword() 'by kagawa Dim i&, j&, k&, l&, m&, n&, r&, s$, s1$, s2$, t$, c1&, c2&, cnt&, tms# tms = Timer m = ActiveCell If m = 0 Then m = 2 * 10 ^ 6 n = 6 s = "ABC2DEF3HJK4LM5N

随机生成运算式2

随机生成运算式,要求: 1.题目避免重复. 2.可定制(数量/打印方式). 3.可以控制一下参数. 要求:是否有乘除法,是否有括号,数值范围,加减有无负数,除法有无余数. 刚开始看到这样一个题目感觉还挺简单,于是从头开始,一步一步的编写代码.但是这次遇到了大麻烦. 我的基本思路是全部用数组来实现,基本是这样的: 1.随机产生num[i]个运算符数组,对应的ch[num[i]]里边放着相应的运算符,类型为string类型. 2.rand1[i][j]数组盛放随机生成参与运算的数,根据算式的形式,运

随机生成30道四则运算-NEW

补充:紧跟上一个随机生成30道四则运算的题目,做了一点补充,可以有真分数之间的运算,于是需要在原来的基础上做一些改进. 首先指出上一个程序中的几个不足:1.每次执行的结果都一样,所以不能每天给孩子出30道一样的题吧!2.没有考虑,如果随机出的是除法,且除数为0的情况.3.没有实现生成真分数的四则运算的功能. 经过分析,决定依次进行改进: 针对问题1:在程序中设置时间种子,即可使得每次程序运行的结果不同. 针对问题2:当判断要生成除法运算时,做一个判断,若除数为0,则重新生成. 针对问题3:定义一

个人作业1:随机生成四则运算

思路:1.利用rand函数随机生成2个100以内随机整数作为两个运算数. 2.随机生成小于5的整数,利用switch函数,0代表整数加法,1代表整数减法,2代表整数乘法,3代表整数除法,4代表真分数运算部分. 3.真分数保证分母大于分子,分母不为0.分子分母均有两个随机数相除获得. 4.将以上设置循环打印输出. 代码: //随机生成30道四则运算(包括真分数) //孔宇航 2016/3/4 #include<iostream> #include<stdlib.h> #include

随机生成MyEclipse注册码

package com.registercode; import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; /** *随机生成MyEclipse注册码 * * @author 邵海雄 * @date 2015-4-16 上午01:37:07 */public class MyEclipseGen { private static final String LL = "De

随机生成一组不重复的随机数组

public string RadomNumArray() { Random r = new Random(); int a = 0; int[] num = new int[6]; string text = ""; for (int i = 0; i < 6; i++) {//循环生成6个数字 a = r.Next(0, 99);//随机生成0到99之间的数字 num[i] = a; for (int k = 0; k < num.Length; k++) {//遍历数