算法 | 如何根据不相等概率[0,1]设计出相等概率的[0,1]?

前言

本文主要介绍如何根据不相等概率[0,1]设计出相等概率的[0,1]

给定一个方法func1,这个方法返回0的概率为p,返回1的概率为1-p

现在要根据func1这个方法,设计出一个新的方法func2,该方法返回0和1的概率都为50%

func1代码如下:

public static int func1() {
    return Math.random() < 0.7 ? 0 : 1;
}
复制代码

思路解析

先来看一下func1这个方法,通过这个方法我们可以得出几个信息:

  1. 方法不可更改,只能被调用。
  2. 方法只返回01,我们并不知道01的概率是多少。
  3. 要想办法从func1中,得出2个概率相等的数字。

func1方法中的内容我们不能更改,而且方法里面的 0.7也有可能是其他的,只知道是固定的,但具体多少也无法得知,只能得到01

要设计的func2方法也是返回01,但是01的概率是相同的,都为50%

那怎么利用func1方法来实现呢?

组合概率

其实实现方法也很简单,只需要调用两次func1方法方法就能得到两个相同的概率数字,我们一起来分析一下。

func1方法可以得到01,调用两次func1方法可以得到哪些组合呢?

调用两次func1方法得到的数据组合为:00011011

再来看下00011011这四组数的概率分别为:ppp*(1-p)(1-p)*p(1-p)*(1-p)

可以看到,虽然我们不知道概率p到底是多少,但至少0110这两组数的概率是相同的都是p*(1-p)

组合概率
00pp
01p*(1-p)
10(1-p)*p
11(1-p)*(1-p)

由此可以得出,我们只要调用两次func1方法,如果生成的是0011,就让他重新生成,如果生成的是0110直接返回即可。

代码实现

经过上面的分析,对func2方法的实现如下:

public static int func2() {
    int res, tmp;
    do {
        res = func1();
        tmp = func1();
    } while (res == tmp);
    return res;
}
复制代码

概率验证

怎么验证一下func2方法返回的01是不是等概率的呢?

验证思路如下:

  1. 初始化一个数组arr,用来存放 01 被调用的次数。
  2. 设置一个循环1千万次,来调用func2()这个方法。
  3. 对比数组arr01元素的个数。
  4. 如果01元素的个数大致相同的话,说明func2()方法返回的01是等概率的。

验证代码如下:

public static void main(String[] args) {
    int times = 10000000;
    int[] arr = new int[2];
    for (int i = 0; i < times; i++) {
        int res = func2();
        arr[res]++;
    }
    System.out.println("元素: 0, 出现的次数为: " + arr[0]);
    System.out.println("元素: 1, 出现的次数为: " + arr[1]);
}
复制代码

多运行几次验证方法,可以发现01的次数是差不多的,也就是说func2()方法返回的01是等概率的。

运行结果如下:

元素: 0, 出现的次数为: 5002123
元素: 1, 出现的次数为: 4997877
复制代码

总结

本文主要介绍如何根据不相等概率[0,1]设计出相等概率的[0,1]

其中主要思想就是根据不相等概率的[0,1]通过组合来生成包含相同概率的两组数的结果00011011,然后从这4组数中只返回相同概率的0110,如果生成的是0011就让他重新再生成直到生成0110

当然,解决方法不可能只有这一种,如果你有更好的方法,欢迎在评论区留言交流~。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值