算法学习随笔-22/12/13

125 阅读2分钟

题目

给定黑盒函数f1()等概率随机生成[1,6]之间的数,求目标函数g()等概率随机生成[1,8]之间的数。 注:限制只能使用f1()的随机方法生成数据,不能使用Math.random()等方法。

思路:

  1. 由目标函数返回值出发,如果我们方法可以等概率返回[0,7]之间的数,那只需要将结果加1就能得到目标函数;
  2. 由于f1()返回[1,6]之间是等概率的,所以返回13和46区间内的值是等概率的,即50%的概率返回[1,3],50%的概率返回[4,6]。
  3. 将思路2转换一下,让f1()方法将返回[1,3]的结果设置为0,将返回[4,6]的结果设置为1,这样我们得到了等概率生成0或1的方法 4.这时我们转变一下思路,位运算中,int类型可以用32位的数来表示,0对应的32位为00000000000000000000000000000000,7对应的32位为00000000000000000000000000000111, 我们取其末尾3位数,即000~111,而思路3可以等概率生成0或1,所以我们将请求思路3的方法三次,将其结果拼成一个数,它的结果也将会是等概率的,这样我们就得到了[0,7]的等概率生成方法,将其结果+1就得到了目标函数g()。

解法:

  1. 给定函数f()
/**
 * 默认方法,不能改,随机等概率返回1-6之间的数,
 * @return int [1,6]
 */
public static int f1() {
    return (int) (Math.random() * 6) + 1;
}

引用f1方法将其获取的值转成0或1

/**
 * 等概率返回0或者1
 * @return int 0或者1
 */
public static int f2() {
    return f1() > 3 ? 1 : 0;
}

引用f2方法将其值拼接成000~111

/**
 * 等概率返回000~111,其实就是等概率返回[0,7]
 * @return int类型 等概率返回[0,7]
 */
private static int f3(){
    return (f2()<<2)+(f2()<<1)+(f2());
}

将f3方法的结果+1得到目标函数g()

/**
 * 目标函数,等概率返回[1,8]之间的整数
 * @return int 
 */
private static int g(){
    int count = f3();
    return count+1;
}

验证方法:

int[] counts = new int[9];
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
    int num = g();
    counts[num]++;
}
for (int i = 0; i < counts.length; i++) {
    System.out.println(i+"这个数出现了 "+counts[i]+"次");
}

结果:控制台运行后可以看出每个数字产生的结果是等概率的。

image.png