问题如上。

这是我被面试的一个题目。

我的第一反应给出的解决的方法是。开启  n 个线程并标记序号,各个线程打印出它的序号。直到有 m 个线程被调度时,停止全部线程。

打印出的序号即是 m 个等概率出现的数字。

面试官听到这个解决的方法,吸了一口凉气。预计心里在想,这小伙疯了!我当时自知这个解决方式不是面试官想要的。于是说了,假设这个 n 非常大,那么就要另

想办法了,由于不可能在一个进程里产生随意多个线程。

想啊想,过了两分钟。还是没有找到解决的方法。面试官非常 nice 让我回去后再想一想。

事实上这个题细想。有些难度。你可能有一种思路:假设能一次性取出 m 个数字。再保证各数字是随机的。则能够满足等概率。但。

。。

怎样一次性取出 m 个数字呢?

一次性生成多个随机数?假设生成的数字有同样则不是等概率的。由于这个数字比其他的数字出现的次数多,则概率大些(虽然你忽略了它出现多次)。

或者还有思路:

每次出一个,保证取 m 次得到的各数字概率相等。听起来。似乎这样的思路要难些。

[解法一]

我们来模拟这个过程。设有一个长度为 m 的辅助数组 B,用来装选中的数字。数组末满时,依次从长度为 n 的数组 A 中每次取一个数字顺序放入 B 中。直到 B 满了。

设对于兴许的每个元素,其装入 B 中的概率为 x。此元素装入 B 中的操作是将它与 B 中的某个元素置换。

则 B 中已经存在的某个元素,继续在 B 中存在的概率为:(1-x) + x*(m-1)/m。即当前取出的元素不进入 B。被直接舍弃,或者当前取出的元素进入 B ,但置换不发生在这个元素身上。

当前 A 中取出的元素。在 B 中存在的概率为 x。即,仅仅要这个元素被选中,就一定会进入 B。

因为要使用每一个元素的概率相等。则有:

x = (1-x) + x*(m-1)/m。故 x = m/(m+1)。

也即。按上面的操作便能保证每个被留下来的元素的概率相等且为 x ,即 m/(m+1)。

[解法二]

事实上。我们考虑一下,这个模型不就是抽奖的模型吗,有 n 张彩票,n 个人每人一张,怎样选出 m 个人出来中奖。即。我们仅仅须要模拟一个公正的抽奖过程便能得到等概率的 m 个人。

我们都知道,抽奖不分先后。每一个人中奖的机率都一样。因此。最简单的做法是将 n 个人随机化排成一列,再取前 m 个人中奖就可以。

那么,我们借助洗牌算法便能做到。那么,怎样得到一个好的洗牌算法呢?一个能够证明是均匀的方法例如以下:

对于第 i 张牌,它以 i/(i+1) 的概率与前面 i 张牌交换,实际操作时,能够生成一个 0 ~ i 之间的随机数。当其不为 i 时运行交换。交换的操作是:将此牌与前面 i 张牌随机交换。

于是,能够证明。第 i 张牌在位置 i ,也即。它没有发生交换的概率为 1 - i/(i + 1)= 1/(i+1)。

第 i 张牌在前面不论什么一个位置的概率为 i/(i+1)*1/i = 1/(i+1) 。可是,我们还须要证明,前 i 张牌中的随意一张在前面
i 个位置中的随意一个位置的概率为 1/(i+1) 才算是证明全然。假设直接入手。这个证明能够想象是相当复杂的。我们使用数学归纳法证明,按上面的操作,随意第 i 张牌被操作完毕后,总共的 i + 1 张牌中的随意一张在0 ~ i 的随意一个位置上的概率为 1/(i + 1)。

证明:

当仅仅有一张牌(第 0 张牌)时,在位置 0 上的概率为 1。

如果第 i 张牌被操作完毕后。总共的 i + 1 张牌中的随意一张在0 ~ i 的随意一个位置上的概率为 1/(i + 1)。

则对于第 i + 1 张牌被操作后:

前面已经证明过。第 i+1 张牌放置在 0 ~ i+1 中的任何位置的概率为 1/(i+2)。

对于 0 ~ i 中的随意一张牌 x,它原先在 0 ~ i 上任何位置的概率为 1/(i + 1)。

x 被换到第 i+1 位置的概率为 (i+1)/(i+2) * 1/(i+1) = 1/(i+2)。x 如今还在 0 ~ i 位置的概率即 1 减去前者,为 : 1 - 1/(i+2)。

而 0 ~ i 共同拥有 i + 1 个位置,故 x 在随意一个位置的概率为:

(1 - 1/(i+2))*1/(i+1) 结果为 1/(i+2)。

于是就证明原结论。因此。这是一个平衡的洗牌算法。

[解法三]

假设我们每次在面临第 i 个元素,不是像解法一中的,维持一个固定的概率去决定该元素是否留下,而是与当前已处理过的元素个数相关,是否能得到一个解法呢?

设总共已处理的个数为 N。当前正要处理的是第 i 个元素。辅助数组为 B。源数组为 A。操作例如以下:

1.当 i <= m 时。元素留下。

2.当 i > m 时,使用概率 m/N 决定元素的去留。假设元素留下。则它随机与 B 中某个元素 x 置换(丢弃x,保留该元素)

证明等概率:

1.当 i = m + 1 时,此元素留下的概率为 m/(m+1)。B 中随意一个元素留下的概率为:1-m/(m+1) + m/(m+1)*(m-1)/m = m/(m+1)。故此时,B 中全部元素的概率为 m/(m+1)。

2.设当已处理 N 个元素时,B 中的元素的概率为 m/N。

则当已处理 N+1 个元素时,当前元素留下的概率为 m/(N+1)。B 中随意一个元素留下的概率为:m/N*(1-m/(N+1) + m/(N+1)*(m-1)/m) = m/(N+1)。最前面的 m/N 表示此元素在 B 中,否则不在 B 中。

故使用上面的操作方法。留下的元素的概率是相等的。且与总共处理的元素的个数是相关的。

这一模型和解法一中的模型是不同样的。注意差别:

解法一中的模型适用于保留下来的元素概率相等。且永远不变。

解法二中的模型适用于保留下来的元素概率相等。但随着处理的元素的个数添加而改变,这也意味着,当须要从未知数目的数据源中取 m 个数字,使其等概率,这样的方法是很适用的。

[解法四]

我们已经有一个心得了,解法方案好像类似于:面临当前元素时。使用一个概率(这个概率可能是动态变化的。或者不变的)决定去留,若留,则与某个已选择的元素置换。以下再给出一种方法。

设 A 为源数组。B 为辅助数组(装入已选择的元素)。A 长度为 n。B 长度为 m。须要从 A 中取 m 个数字放入 B。使它们等概率。

遍历 A,在面临第 i 个元素 x 时,记 p 为还须要从 A 中选出的元素个数。q 为从 x 向后数,将 A 数完的个数。包含 x。决定 x 被选中的概率设置为 p/q。这也能够达到等概率。

1:第 0 个元素被选中的概率为 :m/n

2:第 1 个元素被选中的概率为 :m/n*(m-1)/(n-1) + (1-m/n)*m/(n-1) = m/n

3:第 2 个元素被选中的概率为:... = m/n

....

依此类推,不管哪个元素被选中的概率都为 m/n。以下,我们证明随意一个元素被选中的概率都为 m/n。

假设按上面的思路去证明将非常复杂。可是有一个非常巧妙的证明方法。

我们看这个问题的模型,实际上,它就是一个抽奖模型,如今有一个箱子里面装着 n 张奖券,写着“中”。或“不中”,当中。写着“中”的有 m 张,如今问。第 k 次抽奖,中奖的概率为

多少?这显然为 m/n!

还记得 "抽奖与顺序无关” 吗?于是。我们独立写出第 k 次中奖的概率的表达式:

C(m,1)*A(n-1,m-1) / A(n,m) = m/n。

故,上面的操作方法,随意一个元素被选中的概率都为 m/n。

解法四是对抽奖的全过程进行概率模拟,而解法二是对抽奖的前置处理进行模拟。

此解法的模型适用于保留下来的元素概率固定且相等。

从 n 个数字中选出 m 个不同的数字,保证这 m 个数字是等概率的的更多相关文章

  1. 查找n个数字中的最大值

    闲来无事,试试用arg_list查找n个数字中的最大者. 又因为本人喜欢模板, 所以就早早的写了以下代码, 没有经过严格测试. /*********************************** ...

  2. 小易邀请你玩一个数字游戏,小易给你一系列的整数。你们俩使用这些整数玩游戏。每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字。 例如: 如果{2,1,2,7}是你有的一系列数,小易说的数字是11.你可以得到方案2+2+7 = 11.如果顽皮的小易想坑你,他说的数字是6,那么你没有办法拼凑出和为6 现在小易给你n个数,让你找出无法从n个数中选取部分求和

    小易邀请你玩一个数字游戏,小易给你一系列的整数.你们俩使用这些整数玩游戏.每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字. 例如: 如果{2,1,2 ...

  3. 一串数字中,只有一个数字出现一次,其他数字都出现两次,查找出这个数字(python)(原创)

    背景: 电话面试&手撕代码 2019.03.22 Mufasa 问题: 一串数字中,只有一个数字出现一次,其他数字都出现两次,查找出这个数字 条件: 这串数字是有序数 解决方法: 核心代码只有 ...

  4. 谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。

    谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数. Google2009华南地 ...

  5. 为什么Java7开始在数字中使用下划线

    JDK1.7的发布已经介绍了一些有用的特征,尽管大部分都是一些语法糖,但仍然极大地提高了代码的可读性和质量.其中的一个特征是介绍字面常量数字的下划线.从Java7开始,你就可以在你的Java代码里把长 ...

  6. 一道经典的面试题:如何从N个数中选出最大(小)的n个数

    转载:https://zhidao.baidu.com/question/1893908497885440140.html 这个问题我前前后后考虑了有快一年了,也和不少人讨论过.据我得到的消息,Goo ...

  7. “全栈2019”Java第十六章:下划线在数字中的意义

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. day04_03 题目判断三个数字中的最大值

    num1 = input("Num1:") num2 = input("Num2:") num3 = input("Num3:") 输出三个 ...

  9. SQL Server 从一组数字中随机获取一个数

    很多人在开发需求中想获取一个随机数,或者从一组数字中获取一个数, 这个需求很简单,而且有很多方式可以实现,下面就介绍几种常见的方式,以作为笔记或供有需要的人参考. 比如有一组数字: 57 59 63 ...

随机推荐

  1. github后端开发面试题大集合(三)

    作者:小海胆链接:https://www.nowcoder.com/discuss/3616来源:牛客网 13.软件架构相关问题: 什么情况下缓存是没用的,甚至是危险的? 为什么事件驱动的架构能提高可 ...

  2. php和mysql两种不同方式的分割字符串和类型转换

    一.sql语句1.分割字符串方法:substring_index(字符串,'分隔符',正数从左数起几位/负数从右数起几位); 例如:subtring_index('aa_bb_cc_dd','_',1 ...

  3. Python SGMLParser 的1个BUG??

    首先说一下,我用的是python 2.7,刚好在学Python,今天想去爬点图片当壁纸,但是当我用 SGMLParser 做 <img> 标签解析的时候,发现我想要的那部分根本没获取到,我 ...

  4. Effective STL 学习笔记 Item 17: Swap Trick

    假设有若干对象存于一个 vector 中: class Widget; vector<Widget> vw; 后来由于某些原因,从该容器中删除了若干对象(参考erase-remove id ...

  5. Java测试框架Mockito源码分析

    1.Mockito简介 测试驱动的开发(Test Driven Design, TDD)要求我们先写单元测试,再写实现代码.在写单元测试的过程中,一个很普遍的问题是,要测试的类会有很多依赖,这些依赖的 ...

  6. 【洛谷】P4207 [NOI2005]月下柠檬树

    题解 原来自适应simpson积分是个很简单的东西! 我们尝试分析一下影子,圆的投影还是圆,圆锥的尖投影成一个点,而圆台的棱是圆的公切线,我们把圆心投影出来,发现平面上圆心的距离是两两高度差/tan( ...

  7. hdu 5936 2016ccpc 杭州 - D

    数学题好难啊!!!! 最长长度不超过十位, 折半枚举... 题解 #include<bits/stdc++.h> #define LL long long #define fi first ...

  8. java程序员修炼之道——大牛告诉我们应该好好学习与修炼以下知识与技能

    —————————— ASP.Net+Android+IOS开发..Net培训.期待与您交流! —————————— 一:Java语言学习(对线程(thread),串行化,反射,网络编程,JNI技术, ...

  9. 003 Ajax中传输格式为XML

    一: 1.优缺点 二:大纲 1.结构设计 三:程序 1.xml <?xml version="1.0" encoding="utf-8"?> < ...

  10. Vue中directives的用法

    关于 vue 中 directives 的用法问题,详细可以参考vue官方对directives的解释 当前文章主要讲述directives怎么用,directives做权限按钮的功能 ###1. d ...