02、介绍随机函数

随机函数是平时刷题练习时验证正确性的比较灵魂的方法。
java中提供了Math.random()函数:返回一个[0~1)等概率的一个double类型的值。

1、验证代码

    package com.yubin.algorithms;
    
    /**
     * 介绍随机函数的使用
     * @author YUBIN
     * @create 2021-03-13
     */
    public class Code0007_RandToRand {
    
        public static void main(String[] args) {
            // 验证Math.random()函数[0,1)是等概率的
            int testTimes = 10000000;
            int count = 0;
    
            for (int i = 0; i < testTimes; i++) {
                if (Math.random() < 0.75) { // 其概率应该约等于0.75
                    count++;
                }
            }
            System.out.println((double)count / (double)testTimes);
    
            System.out.println("===========================");
    
            // [0,1)*8 => [0,8)
            count = 0;
            for (int i = 0; i < testTimes; i++) {
                if (Math.random() * 8 < 5) { // 其概率应该约等于 5/8=0.625
                    count++;
                }
            }
            System.out.println((double)count / (double)testTimes);
    
            System.out.println("===========================");
    
            int k = 9;
            // [0,k) 相当于 [0,l-1]
            int[] counts = new int[k];
            for (int i = 0; i < testTimes; i++) {
                int ans = (int) (Math.random() * k);
                counts[ans]++;
            }
            for (int i = 0; i < k; i++) {
                System.out.println(i + "这个数,出现了" + counts[i] + "次");
            }
            System.out.println("===========================");
        }
    }

2、题目一:如何利用Math.random()函数,把得到[0,x)范围上的数的概率从x调整成x2

题目分析:经过上面的验证Math.random()随机函数[0,1)范围上概率是相等的,对应的0 ~ x范围的概率就是x,那么如何让0 ~ x的概率变成x2呢?
利用Math.max(Math.random(), Math.random())
Math.max(a1,a2); 只有当a1和a2两个值都在0 ~ x范围内的时候值才会在0 ~ x范围内,这样[0,x)的概率就变成x2了。

    private static double xToPower2() {
      return Math.max(Math.random(), Math.random());
    }

注意:如果这里改成Math.min()函数的话,概率就变成 1-(1-x)2

3、题目二:从1 ~ 5随机到1 ~ 7随机

题目分析:程序中已提供一种1 ~ 5的随机是等概率的方法,如何利用该函数实现1 ~ 7的随机是等概率的。
其实这个题目有一个限制就是1~7的等概率随机数不能使用 (int)(Math.random()*7)+1的方式,只能使用现成的方法。
思路:
已知函数是等概率返回[1,5]的整数
那么1,2,3,4,5的概率分别是20%, 如果我使用1和2 表示0; 4和5表示1 当遇到3的时候再次随机即将得到3的概率分摊到其它4个数上面,此时得到1、2、4、5的概率都是25%,因此得到0的概率就是50%,得到1的概率也是50%。
通过[1,5]等概率函数可以得到一个0,1等概率函数,然后再利用二进制的方式可以拿到一个0 ~ 7的等概率函数
000,001,010,011,100,101,110,111。 因为7这个数至少需要3位来表示。
代码实现:

    /**
     * 返回[1,5]的等概率随机数
     * 假设该方法是lib里面,不能修改
     * @return
     */
    private static int f1() {
        return (int) (Math.random() * 5) + 1;
    }
    
    /**
     * 随机机制,等概率返回0和1 只能使用f1函数
     * 分析 f1函数是等概率返回[1,5]的整数
     * 那么1,2,3,4,5的概率分别是20%, 如果我使用1和2 表示0; 4和5表示1 当遇到3的时候再次随机即将得到3的概率分摊到其它4个数上面,
     * 此时得到1、2、4、5的概率都是25%,因此得到0的概率就是50%,得到1的概率也是50%
     *
     * @return
     */
    private static int f2() {
        int ans = 0;
        do {
            ans = f1();
        } while (ans == 3);
    
        return ans < 3 ? 0 : 1;
    }
    
    // 得到000 ~ 111 做到等概率 0 ~ 7等概率返回一个 每一个数的概率是1/8
    private static int f3() {
        return (f2() << 2) + (f2() << 1) + (f2() << 0);
    }
    
    // 0 ~ 6等概率返回一个
    private static int f4() {
        int ans = 0;
        do {
            ans = f3();
        } while (ans == 7);
    
        return ans;
    }
    
    // 1 ~ 7等概率返回一个
    private static int g() {
        return f4() + 1;
    }

同理:从a ~ b随机到c ~ d随机这个题目也可以使用上面这个方法来实现。
将a ~ b变成01等概率发生器 ,将c ~ d变成0 ~ (d-c) 这时再看d-c需要几个二进制位, 同时如果超过d-c部分的重做即可

4、题目三:01不等概率随机到01等概率随机

分析:01不等概论,但是可以知道0和1是固定概率的,这样的话我们使用两位来表示
00,01,10,11
这每个数出现的概率都是第一位的概率 * 第二位的概率, 而已知的函数0和1虽然概率不一样但是0的概率*1的概率是一样的,这样01,10就是等概率的了, 使用01表示0,10表示1,其它情况重做即可,这样最后就能得到一个01的等概率随机。
代码实现:

    // 已知的01不等概论函数,但是0和1的概率是固定的
    private static int x() {
        return Math.random() > 0.84 ? 0 : 1;
    }
    
    // 通过x函数得到01的等概率随机
    private static int y() {
        int ans = 0;
        do {
            // 第一次调用x函数
            ans = x();
        } while (ans == x()); // 第二次调用x函数 两次返回的结果不一样则说明要么是01 要么是10
    
        return ans;
    }

你可能感兴趣的:(02、介绍随机函数)