【算法】【算法杂谈】已知[1,m]的等概率函数,求[1,n]的等概率函数
目录
- 前言
- 问题介绍
- 解决方案
- 代码编写
- java语言版本
- c语言版本
- c++语言版本
- 思考感悟
- 写在最后
前言
当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~
在此感谢左大神让我对算法有了新的感悟认识!
问题介绍
原问题
给定一个等概率随机1-5的函数,在不使用任何额外的随机函数下,通过rand1To5实现rand1To7函数
补充题目
给定一个以p概率产生0,1-p概率产生1的随机函数rand01P,通过该函数实现等概率的rand1To6
进阶题目
给定一个随机产生1-M的随机函数rand1ToM,请依次来实现rand1ToN的随机函数
解决方案
原问题:
1、首先求出等概率的0-4,即rand1To5()-1
2、再求出等概率的[0,5,10,15,20],即 (rand1To5()-1)* 5 (扩容)
3、此时可以求出等概率的0-24,即 (rand1To5()-1)* 5 + rand1To5()-1 (插空)
4、再mod6即可得到0~6的等概率,再+1即可得到1-7的等概率函数了!
最后公式:((rand1To5()-1)* 5 + rand1To5()-1) % 6 + 1
补充题目
1、首先需要获取一个能够出现等概率的函数,才能解决等概率的问题
2、首先0和1无法一次调用出现等概率,但是调用两次,可能的结果为 00(概率:p^2) 01(概率:p(1-p))10(概率:p(1-p)) 11((1-p) ^2),由此发现10和01的出现概率相同!利用这个即可获取一个01的等概率函数
3、如果有了等概率的01,则能通过原问题中的解法就可以求的等概率的05,也就能求出等概率的1-6了
进阶题目
1、首先将n-1转化成m进制的数
2、申请一个长度为32位的int类型数组,作为m进制的结果
3、从左向右进行等概率的获取0-(m-1)的数,也就是高位先等概率生成,如果中途发现整体数大于0了,则直接放弃,从头开始
4、最终获取到的结果再转成10进制即可
代码编写
java语言版本
原问题:
方法一:
/*** 随机返回1到5之间的数* @return*/public static int random1to5Cp1() {return (int) (Math.random() * 5 + 1);}/*** 以p的概率出现0和1* @param p* @return*/public static int randomP01Cp1(double p) {return Math.random() < p ? 0 : 1;}/*** 随机返回1到7之间的数* 要求:1、仅使用random1to5实现2、必须等概率* 方法:插空法、筛选法* @return*/public static int random1to7Cp1() {int p = 0;while ((p = (random1to5Cp1() - 1) * 5 + (random1to5Cp1() - 1)) > 20) {p = (random1to5Cp1() - 1) * 5 + (random1to5Cp1() - 1);}return (int)(p%7) + 1;}/*** 等概率实现1到6的随机函数* 要求1、仅使用randomP01Cp1实现2、等概率* @return*/public static int random1to6Cp1() {// 0-6int p = 0;while ((p = get03Cp1()*2 + (get01Cp1() + 1)) > 6) {p = get03Cp1()*2 + (get01Cp1() + 1);}return (int)(p%6) + 1;}/*** 将不等概率的变成等概率返回0和1* @return*/private static int get01Cp1() {int num1 = 0, num2 = 0;while (((num1 = randomP01Cp1(0.83)) ^ (num2 = randomP01Cp1(0.83))) != 1);return num1;}/*** 等概率获取0123* @return*/private static int get03Cp1() {return get01Cp1() * 2 + get01Cp1();}/*** 给定一个m,返回1-m等概率出现* @param m* @return*/private static int get1ToM(int m) {return (int)(Math.random() * m) + 1;}/*** 通过等概率的1-m,求等概率的1-n* @param m* @param n* @return*/private static int get1TonFromM(int m, int n) {// 首先求用m进制表示的n-1int[] mSysN = getSysMNum(n-1, m);// 产生一个小于mSysN的m进制的数int[] mSys1ToN = getSysM1ToN(mSysN, m);// 再转回到10进制return get10SysFromM(mSys1ToN, m) + 1;}/*** 从m进制转回到10进制* @param mSys1ToN* @param m* @return*/private static int get10SysFromM(int[] mSys1ToN, int m) {int index = mSys1ToN.length-1;int res = 0;while (index >= 0) {res += Math.pow(m, (mSys1ToN.length-1) - index) * mSys1ToN[index];index--;}return res;}/*** 等概率随机获取一个小于mSysN的值* @param mSysN* @param m* @return*/private static int[] getSysM1ToN(int[] mSysN, int m) {// 找到左边第一个不为0的int start = 0;while (mSysN[start] == 0) {start++;}// 生成数游标int index = start;int[] res = new int[32];// 表示上一个值是否和mSysN相等,如果相等,则这波还要继续生成,如果不相等说明已经大于了直接随机生成即可boolean isLastEquals = true;// 从高位开始随机获取while (index != mSysN.length) {// 先生成res[index] = get1ToM(m)-1;// 判断该位置的上一个是否相等if (isLastEquals) {// 相等则该位置需要比较if (res[index] > mSysN[index]) {// 说明生成的超过了,归位,全部重来index = start;isLastEquals = true;continue;}else {isLastEquals = res[index] == mSysN[index];}}// 该位置不需要比较index++;}return res;}/*** 用m进制表示value* @param value* @param m* @return*/private static int[] getSysMNum(int value, int m) {int[] res = new int[32];int mod = value;int tem = value;int index = res.length-1;while (tem != 0) {res[index--] = mod % m;tem = mod/m;mod = mod%m;}return res;}public static void main(String[] args) {int[] ints = new int[5];for (int i = 0; i < 100 ; i++ ){//System.out.println(get1TonFromM(7, 5));ints[get1TonFromM(7,5)-1] ++;//System.out.println();}CommonUtils.printArr(ints);//System.out.println(String.format("%.2f", 0.0124124124));}
c语言版本
正在学习中
c++语言版本
正在学习中
思考感悟
1、原问题主要讲述了一个思想就是如果用小范围的等概率扩容到大范围的等概率,其中先用乘法扩容,扩容不是随便扩容的,扩容的大小刚还要能够让自己插空,也就是说 0-4的等概率扩容必须是0,5,10,15,20,只有这样才能将0-4插入到空隙中形成等概率的0-24,之后通过mod来缩小范围即可
2、补充问题主要讲述了如何通过非等概率获取等概率的方法,那就是通过两次的组合发现等概率的事件来制造等概率函数
3、最后一道题看似是原问题的拓展版本,其实实现方式反而是另一种角度来看这类问题了,进阶问题其实讲述了该类问题可以通过进制方式来解决,首先将目标变成m进制,之后用0-m-1的随机来生成进制的每一位,并不断判断是否越界,直到没有越界生成一个符合的数之后返回这个数,整体上还是有序的。
写在最后
方案和代码仅提供学习和思考使用,切勿随意滥用!如有错误和不合理的地方,务必批评指正~
如果需要git源码可邮件给2260755767@qq.com
再次感谢左大神对我算法的指点迷津!
相关文章:
【算法】【算法杂谈】已知[1,m]的等概率函数,求[1,n]的等概率函数
目录 前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本 思考感悟写在最后 前言 当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识! 问题介…...

【Python】Python中的列表,元组,字典
文章目录 列表创建列表获取元素修改元素添加元素查找元素删除元素列表拼接遍历列表切片操作 元组创建元组元组中的操作 字典创建字典添加/修改元素删除元素查找字典的遍历合法的key类型 列表 列表是一种批量保存数据的方式,列表使用[]表示 创建列表 创建两个空列…...

分布式系统概念和设计-分布式对象和远程调用
分布式系统概念和设计 分布式对象和远程调用 能够接收远程方法调用的对象称为远程对象,远程对象实现一个远程接口。 调用者和被调用对象分别存在不同的失败可能性,RMI和本地调用有不同的语义。 中间件 在进程和消息传递等基本构造模块之上提供编程模型的…...

11-FastDFS
一 为什么要使用分布式文件系统 单机时代 初创时期由于时间紧迫,在各种资源有限的情况下,通常就直接在项目目录下建立静态文件夹,用于用户存放项目中的文件资源。如果按不同类型再细分,可以在项目目录下再建立不同的子目录来区分…...

Word这样用,提高效率不加班
Word这样用,提高效率不加班 今天给大家分享23条Word文档的应用小技巧。对于大家来说,掌握些技巧能够效率百倍,何乐不为? 这些技巧是本人通过整理一直在用并且使用频率较高的,也希望能帮到大家。有兴趣的小伙伴可以自己…...

【Linux】调试器---gdb的使用
文章目录 一.背景知识二.安装gdb三.gdb的用法使用须知gdb的常用指令1.进入调试2.退出调试操作3.显示源代码4.设置断点breakPoint5.查看断点信息/禁用断点/开启断点/删除断点6.运行程序,开始调试run7.查看变量8.其它重要命令 一.背景知识 程序的发布方式有两种&…...

MySQL数据库之表的增删改查(进阶)
目录 1. 数据库约束1.1 约束类型1.2 NULL约束1.3 UNIQUE:唯一约束1.4 DEFAULT:默认值约束1.5 PRIMARY KEY:主键约束1.6 FOREIGN KEY:外键约束1.7 CHECK约束 2 表之间的关系2.1 一对一2.2 一对多2.3 多对多 3 新增4 查询4.1 聚合查…...
Nginx从开始到结束,简单到小白都能懂哦
绪论 大家好,很高兴能够为大家带来这篇关于Nginx配置的新手指南。在这篇博客中,我们将通过简单明了的图文教程,帮助大家快速上手Nginx配置,解锁Nginx的各种神奇功能! 一、Nginx简介 Nginx是一款功能强大的web服务器…...
Qt——Qt控件之按钮-QDialogButtonBox对话框按钮盒子控件的使用总结(例程:自定义按钮)
【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C++语言开发基础总结》 《从0到1学习嵌入式Linux开发》 《QT开发实战》 《Android开发实战》...

数据库学习-常用的SQL语句
背景: 汇整一下自己学习数据库过程中常见的题目及语句。 一.实例分析题 二.简单SQL查询: 1):统计每个部门员工的数目select dept,count(*) from employee group by dept;2):统计每个部门员工的数目大于一个的记录se…...
5种获取JavaScript时间戳函数的方法
5种获取JavaScript时间戳函数的方法 一、JavasCRIPT时间转时间戳方法一:Date.now()方法二:Date.parse()方法三:valueOf()方法四:getTime()方法五:Number 二、js时间戳转时间方法一:生成2022/1/18 上午10:09…...
图的宽度优先遍历
文章目录 图的宽度优先遍历程序设计程序分析图的宽度优先遍历 【问题描述】根据输入图的邻接矩阵A,给出图的宽度优先遍历序列; 【输入形式】第一行为图的结点个数n,第二行输入顶点的信息,每个顶点用一个字符表示,接下来的n行为图的邻接矩阵A。其中A[i][j]=1表示两个结点邻…...

企业AD域(域控服务器)的安装和配置详细教程
一、环境以及工具准备 软件:VMWare Workstation 2016 ( 下载链接:https://pan.baidu.com/s/1iX1VRilerYPGbGvX4pvaKw 提取码:75R6 ) 镜像:Windows Server 2016 ( 下载地址ÿ…...

面试官:一千万的数据,你是怎么查询的?
面试官:一千万的数据,你是怎么查询的? 1 先给结论 对于1千万的数据查询,主要关注分页查询过程中的性能 针对偏移量大导致查询速度慢: 先对查询的字段创建唯一索引 根据业务需求,先定位查询范围(…...

IntelliJ 上 Azure Event Hubs 全新支持来了!
大家好,欢迎来到 Java on Azure Tooling 的3月更新。在这次更新中,我们将介绍 Azure Event Hubs 支持、Azure Functions 的模板增强,以及在 IntelliJ IDEA 中部署 Azure Spring Apps 时的日志流改进。要使用这些新功能,请下载并安…...

性能测试,监控磁盘读写iostat
性能测试,监控磁盘读写iostat iostat是I/O statistics(输入/输出统计)的缩写,iostat工具将对系统的磁盘操作活动进行监视。它的特点是汇报磁盘活动统计情况,同时也会汇报出 CPU使用情况。同vmstat一样,ios…...

steam游戏搬砖项目怎么做?月入过万的steam搬砖项目教程拆解
steam游戏搬砖项目怎么做?月入过万的steam搬砖项目教程拆解 大家好,我是童话姐姐,今天继续来聊Steam搬砖项目。 Steam搬砖项目也叫CSGO搬砖项目,它并不是什么刚面世的新项目,是已经存在至少七八年的一个资深老牌项目。这个项目…...

协同运力、算力、存力,加速迈向智能世界
2023年4月20日,华为在HAS2023期间举办“迈向智能世界”主题论坛,吸引了来自全球的分析师、专家学者及媒体与会。会上,华为ICT战略与Marketing总裁彭松发表了“持续技术创新,加速迈向智能世界”的主题演讲。 华为ICT战略与Marketin…...

被裁员了,要求公司足额补缴全部公积金,一次补了二十多万!网友兴奋了,该怎么操作?...
被裁员后,能要求公司补缴公积金吗? 一位网友问: 被裁员了,要求公司把历史公积金全部足额缴纳,现在月薪2.3万,但公司每个月只给自己缴纳300元公积金,结果一次补了二十多万,一次性取出…...

家庭智能插座一Homekit智能
传统的灯泡是通过手动打开和关闭开关来工作。有时,它们可以通过声控、触控、红外等方式进行控制,或者带有调光开关,让用户调暗或调亮灯光。 智能灯泡内置有芯片和通信模块,可与手机、家庭智能助手、或其他智能硬件进行通信&#x…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...
从实验室到产业:IndexTTS 在六大核心场景的落地实践
一、内容创作:重构数字内容生产范式 在短视频创作领域,IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色,生成的 “各位吴彦祖们大家好” 语音相似度达 97%,单条视频播放量突破百万…...
Python爬虫实战:研究Restkit库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...

Java中HashMap底层原理深度解析:从数据结构到红黑树优化
一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一,是基于哈希表的Map接口非同步实现。它允许使用null键和null值(但只能有一个null键),并且不保证映射顺序的恒久不变。与Hashtable相比,Hash…...
在ubuntu等linux系统上申请https证书
使用 Certbot 自动申请 安装 Certbot Certbot 是 Let’s Encrypt 官方推荐的自动化工具,支持多种操作系统和服务器环境。 在 Ubuntu/Debian 上: sudo apt update sudo apt install certbot申请证书 纯手动方式(不自动配置)&…...