用randX 实现 randY(X < Y)

其中,randN表示等概生成[1,N]的数
从一个力扣上的例子来引入吧

470. 用 Rand7() 实现 Rand10()

最直观的想法是用rand7()+rand7()-1去生成[1, 13]的数,然后只取[1, 10],但实际上这里的每个数并不是等概的,例如1的概率是1/49(1+1),但10的概率是4/49(4+7,5+6,6+5,7+4)。所以该方法并不可行。
事实上,可以把第一个rand7()和第二个rand7()分别看成两个独立的随机变量,假设分别为A和B,那么对于A∈[1,7]和B∈[1,7],可以作成一张二维表,一共有7*7=49种等概情况。

那么实际上我们只需在这49种情况中取出10种,其他的设为拒绝域(即不符合要求就重新采样)。但是这样设置,接收域概率太小了,可能导致我们的多次尝试。因此可以考虑对现有的49种情况归类,因为共10类,49/10=4…9,因此每类可以包含4种情况,剩下多出来的9类为拒绝域。

对于每种情况,我们需要进行一个编号,最简单的编号方法就是逐行从左到右编号。可以理解为,对于A=a,B=b,编号f(a,b)的映射为

f(a,b) = (a-1)*7 + b ∈[1,49]

这样就把所有情况映射到了区间[1,40]内(大于40的被舍弃)。
接着再对10取余,余数[0, 9]分别对应10种情况。
通过这种方式,可以最大化的利用出现概率。

深入分析

该问题的本质是对二元随机分布共7*7=49种情况去找一个合适的映射,等概地映射到10类。前面最直观的想法用rand7()+rand7()-1,实际上是找到映射f(a,b)=a+b ∈[2, 14],但这里值域的每个值的概率并不相等,所以这种映射是错误的。而用f(a,b)=(a-1)*7 + b 这种编号映射,十分直观,又可以最大化的利用概率。
合理映射不止一种,具体看如何设计了,例如,力扣某大佬设计出的下面这种,也是可以的(虽然多了一些拒绝域):

推广:用randX 和 randY实现 randXY(X < Y)

对于任意两个随机器 randX 和 randY,总共对应有XY种情况,可以组合成一个 randXY 的随机器,具体地:

randX*Y = (randX-1) * Y + randY

而任意的 randX,可以由其整数倍的随机器 randY = k*X 通过 下式得到

randX = randY % X + 1

用randY 实现 randX(Y>X)

若Y恰好是X的整数倍,则用上式即可;
若非整数倍,则先设置接收域和拒绝域,接收域为X的整数倍。那么取能够使得k*X<=Y的最大整数值k,充分扩大接收域范围。
例如在上面的例子中 rand49 -> rand10 ,取k=Y//10=3。

优化:充分利用拒绝域

在前面的例子中,对于位于拒绝域[41, 49]的元素,是采用直接抛弃的策略,重新生成随机数,这样效率是比较低的。但实际上,我们可以利用这个拒绝域,做一些延伸性的工作,尽可能提高命中概率。
对于不幸落于拒绝域的情况(元素超过40),可以认为其是一个rand9的随机生成器,那么可以再利用rand7,生成[1,63],然后取[1,60]为接收域,[61,63]为拒绝域。若再次不幸落于这个拒绝域中,我们又可以重复上一步的思路,认为这是一个rand3的随机器,利用rand7,生成[1,21],取[1,20]为接收域,[21,21]为拒绝域。此时若又不幸落于拒绝域21中,那么就是一个特定的数不再是随机数了。那么只能重头来过。
通过以上操作,我们可以算一下概率,三次都不命中的概率为:

而如果不利用拒绝域,三次都不命中的概率为:

前者明显更小!!!
附一张官方题解计算的命中需调用rand7()次数的期望:
优化后:

优化前:

但这个是否是一个普适的结论,仍需严谨考证,也欢迎大家在下面留言一起讨论~

—————————————————————————————————————————————
参考:
从最基础的讲起如何做到均匀的生成随机数
官方题解:用 Rand7() 实现 Rand10()

力扣随机数randX——透过现象看本质之二元独立随机分布相关推荐

  1. 传统金融PK互联网 必须透过现象看本质

    传统金融PK互联网 必须透过现象看本质 面对越来越热的互联网金融,传统金融业内人士与互联网的发生激烈了冲突,中国近期的经济疲软似乎也变成了互联网金融的原罪之一,但事实真是如此吗? width=&quo ...

  2. 软件架构设计案例_透过现象看本质:常见的前端架构风格和案例

    所谓软件架构风格,是指描述某个特定应用领域中系统组织方式的惯用模式.架构风格定义一个词汇表和一组约束,词汇表中包含一些组件及连接器,约束则指出系统如何将构建和连接器组合起来.软件架构风格反映了领域中众 ...

  3. 透过现象看本质,如何针对用户做好需求分析

    对于刚入门的产品经理而言,很容易出现设计出来的产品功能不达用户预期的情况.这里面一部分原因是由于需求分析没做到位,忽略了事情背后的本质.那么下面我们看看如何做好需求分析. 透过现象看本质 我们只有透过 ...

  4. 大道至简之四:透过现象看本质

    大道至简:透过现象看本质 --投资总结之四         时寒冰 研究趋势是一件充满挑战和趣味的事情.     我深信,很多现象是有规律可循的.     但是,对于趋势的判断尤其提前做出的判断,短期 ...

  5. 大道至简:透过现象看本质

    大道至简:透过现象看本质 --投资总结之四         时寒冰 研究趋势是一件充满挑战和趣味的事情.     我深信,很多现象是有规律可循的.     但是,对于趋势的判断尤其提前做出的判断,短期 ...

  6. 透过现象看本质:喧闹的中国电子商务

    吴军先生做<透过现象看本质:喧闹的中国电子商务>主题演讲,剖析中国电子商务行业的现状和格局,预测未来行业趋势,并针对传统企业.中小企业的具体情况,给出一些策略上的建议. 以下是吴军先生的现 ...

  7. 黄金思维圈,养成透过现象看本质的能力

    loonggg 读完需要 3 分钟 速读仅需 1 分钟 大家好,我是你们的校长. 今天我想给大家聊一聊关于思考,关于黄金思维圈的问题.如果你有了黄金思维圈的思维,带着目的去做一件事情,不仅仅会养成透过 ...

  8. ChatGPT爆火背后的原因:透过现象看本质

    ChatGPT爆火背后的原因:透过现象看本质 随着人工智能技术的快速发展,我们已经在许多领域看到了AI的身影.在最近的一段时间里,ChatGPT成为了一个引起广泛关注的现象.ChatGPT以其强大的自 ...

  9. 透过现象看本质 | GPT爆火的背后

    前言: 近年来,GPT(Generative Pre-trained Transformer)作为一种革命性的语言模型,以其强大的文本生成能力和广泛的应用领域引发了全球范围内的热议.然而,GPT爆火的 ...

最新文章

  1. 谈谈对数据库中ACID、CAP、BASE的认识
  2. [转]独立窗口打开多个Excel文件
  3. MyBatis-Plus selectMapsPage报错
  4. 洛谷P1095守望者的逃离题解-伪动态规划/贪心
  5. 从程序员到项目经理,没有捷径可走
  6. Python操作git
  7. linux信号量简介
  8. 在阿里云的ubuntu上部署个人服务
  9. Http压力测试之ab
  10. lambda 对象初始化器 集合初始化器
  11. easyui 修改单元格内容_jquery easyui datagrid实现增加,修改,删除方法总结
  12. UNIX环境高级编程习题——第三章
  13. 对计算机病毒防治最科学的方法是,计算机病毒防治(复习-3
  14. Oracle Primavera P6EPPM Mobile/App 安卓移动端分享(长期更新)
  15. javascript定时器的计时事件
  16. Error:Some file crunching failed, see logs for details Error:Execution failed for task ':app:mergeDe
  17. 老徐WEB:js入门学习 - 认识javascript
  18. 进入docker容器的方法
  19. 云原生可观测性平台-云监控
  20. 古文字识别助手与众包平台——项目博客五

热门文章

  1. leet234.回文链表
  2. iOS-App移交(更换app开发者账号)
  3. The DELETE statement conflicted with the REFERENCE constraint
  4. 自动化测试工具 Selenium WebDriver 入门教程
  5. mysql级联更新优化_mysql级联更新
  6. VMware虚拟机快速复制多个Linux系统
  7. 「PyTorch自然语言处理系列」7. 自然语言处理的进阶序列模型
  8. nodeBB项目的目录结构简介(nodeBB系列三)
  9. Leetcode 1925. Count Square Sum Triples [Python]
  10. 编译程序、解释程序、汇编程序和编译、解释的概念