zoukankan      html  css  js  c++  java
  • OptimalSolution(9)--其他问题(1)

      一、从5随机到7及其扩展

      题目1:给定一个等概率随机产生1~5的随机函数rand1to5:

        public int rand1To5() {
            return (int)(Math.random() * 5) + 1;
        }

      除此之外,不能使用任何额外的随机机制,请用rand1To5实现等概率随机产生1~7的随机函数random1To7。

      解法:

      第一步:rand1To5()等概率随机产生1,2,3,4,5

      第二步:rand1To5()-1等概率随机产生0,1,2,3,4

      第三步:(rand1To5()-1)*5等概率随机产生0,5,10,15,20

      第四步:(rand1To5()-1)*5 + rand1To5()-1等概率随机产生0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24

      第五步:如果第四步产生的结果大于20,则重复进行第四步,直到产生的结果在0~20之间,同时可以知道出现21~24的概率,会平均分配到0~20上。

      第六步:第五步会等概率随机产生0~20,所以第五步的结果进行%7操作,就会等概率产生0~6

      第七步:将第六步的结果再加1,就会等概率随机产生1~7

        public int rand1To6() {
            int num = 0;
            do {
                num = (rand1To5() - 1) * 5 + rand1To5() - 1;
            } while (num > 20);
            return num % 7 + 1;
        }

      

      题目2:给定一个以p概率产生0,以1-p概率产生1的随机函数random01p:

        public int rand01p() {
            double p = 0.83;
            return Math.random() < p ? 0 : 1;
        }

      除此之外,不能使用任何额外的随机机制,请用rand01p实现等概率随机产生1~6的随机函数random1To6。

      分析:

        不断重复执行rand01p()函数,直到第一次之后出现的数与第一次出现的数不同为止。

        rand01p()第一次产生的数为0的概率为p(1-p),rand01p第一次产生的数为1的概率为(1-p)p,则说明可以使用rand01()方法等概率产生0和1

        public int rand01() {
            int num;
            do {
                num = rand01p();        
            } while (num == rand01p());
            return num;
        }

      解法:

        第一步:rand01()等概率随机产生0和1

        第二步:rand01()*2等概率随机产生0和2

        第三步:rand01()*2+rand01()等概率随机产生0,1,2,3,即生成rand0To3()方法

        public int rand0To3() {
            return rand01() * 2 + rand01();
        }

        第四步:rand0To3()*4+rand0To3()等概率随机产生0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

        第五步:如果第四步产生的结果大于11,则重复进行第四步,直到产生的结果在0~11之间,那么12~15的概率就会平均分配到0~11上

        第六步:对第五步的结果进行%6操作,就会等概率随机产生0~5,然后再对这个结果加1,就会等概率随机产生1~6

        public int rand1To6ByRand0To3() {
            int num = 0;
            do {
                num = rand0To3() * 4 + rand0To3();
            } while (num > 11);
            return num % 6 + 1;
        }

      题目3:给定一个等概率随机产生1~M的随机函数rand1ToM:

        public int rand1ToM(int m) {
            return (int)(Math.random() * m) + 1;
        }

      除此之外,不能使用任何额外的随机机制,有两个输入参数,分别为m和n,请用rand1ToM(m)实现等概率随机产生1~n的随机函数rand1ToN。

      分析:

        总结题目1和题目2的解法

        如果要产生1~7,那么考虑随机生成0~6,因此等概率产生0~24(插空),然后等概率产生0~20(筛),进行%7操作,结果加1

        如果要产生1~6,那么考虑随机生成0~5,因此等概率产生0~15(插空),然后等概率产生0~11(筛),进行%6操作,结果加1

        针对题目3,可以有,如果M≥N,直接进入筛过程;如果M<N,先进入插空过程,直到产生比N大的随机范围后,再进入筛过程。

      解法:

        调用k次rand1ToM(m),生成有k为的M进制数,并且产生的范围要大于或等于N。例如,题目1中由随机5到随机7,首先生成0~24范围内的数,也就是0~(5²-1),在把范围扩到大于或等于N的级别之后,如果真实生成的数大于或等于N,就忽略,只留下小于或等于N的数,那么在0~N-1上就可以做到均匀分布。

        以m=5,n=7即由随机5产生随机7为例:

        第一步:将10进制的n-1转换成m进制数,即将7-1=6转换成5进制数,也就是11

        // 将10进制的value转换成m进制数
        public int[] getMSysNum(int value, int m) {
            int[] res = new int[32];
            int index = res.length - 1;
            while (value != 0) {
                res[index--] = value % m;
                value /= m;
            }
            return res;
        }

        第二步,等概率产生一个0~6的随机数,用5进制表示,也就是0~11的随机数,例如随机数6用10表示

        // 等概率随机产生一个0~nMSys范围的数,只不过是用m进制表达的
        public int[] getRanMSysNumLessN(int[] nMSys, int m) {
            int[] res = new int[nMSys.length];
            int start = 0;
            while (nMSys[start] == 0) {
                start ++;
            }
            int index = start;
            boolean lastEqual = true;
            while (index != nMSys.length) {
                res[index] = rand1ToM(m) - 1;
                if (lastEqual) {
                    if (res[index] > nMSys[index]) {
                        index = start;
                        lastEqual = true;
                        continue;
                    } else {
                        lastEqual = res[index] == nMSys[index];
                    }
                }
                index++;
            }
            return res;
        }

        第三步:将第二步产生的0~6范围内的5进制数转换成十进制输出:将10转换成6输出

        // 把m进制数转成十进制数
        public int getNumFromMSysNum(int[] mSysNum, int m) {
            int res = 0;
            for (int i = 0; i < mSysNum.length; i++) {
                res = res * m + mSysNum[i];
            }
            return res;
        }

      总方法rand1ToN:

        public int rand1ToN(int n, int m) {
            int[] nMSys = getMSysNum(n - 1, m);
            int[] randNum = getRanMSysNumLessN(nMSys, m);
            return getNumFromMSysNum(randNum, m) + 1;
        }

      

      二、一行代码求两个数的最大公约数

      题目:给定两个不等于0和整数M和N,求M和N的最大公约数

      解法:根据欧几里得算法(又叫辗转相除法),如果q和r分别是m除以n的商及余数,即m=nq+r,那么m和n的最大公约数等于n和r的最大公约数。

        public int gcd(int m, int n) {
            return n == 0 ? m : gcd(n, m % n);
        }

      三、判断一个点是否在矩形内部

      四、判断一个点是否在三角形内部

      五、折纸问题

      六、设计有setAll功能的哈希表

      七、设计可以变更的缓存结构

      八、设计RandomPool结构

      九、调整[0,x)上数出现的概率

      十、整数数组的最小不可组成和

      十一、从N个数中等等概率带你M个数

      十二、判断一个数是否为回文数

      十三、在有序旋转数组中找到最小值

      十四、在有序旋转数组中找到一个数

      十五、一种消息接收并打印的结构设计

      十六、在两个长度相等的排序数组中找到上中位数

      十七、两个有序数组间相加和Top K问题

      十八、蓄水池算法

      

      

  • 相关阅读:
    STL
    STL
    视觉里程计- 位姿
    opencv
    C++ 智能指针auto_ptr、shared_ptr、unique_ptr《三》-----智能指针的选择
    C++ 智能指针auto_ptr、shared_ptr、unique_ptr《二》-----为何unique_ptr优于auto_ptr
    C++ 智能指针auto_ptr、shared_ptr、unique_ptr《一》-----智能指针初识
    DBow中,TF-IDF了解
    网络爬虫(CrawlSpider)
    python3 获取cookie
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/9646502.html
Copyright © 2011-2022 走看看