数据结构---红包分配算法

2023-11-18

问题如下:

  1. 所有人抢到的金额之和要等于红包金额,不能多也不能少。
  2. 每个人至少抢到1分钱。
  3. 要保证红包拆分的金额尽可能分布均衡,不要出现两极分化太严重的情况。

错误解法

每次拆分的金额 = 随机区间[1分, 剩余金额-1分]

存在的问题:

  1. 第1个人抢到金额的随机范围是[0.01,99.99]元,在正常的情况下,抢到金额的中位数是50元。假设第1个人随机抢到了50元,那么剩余金额是50元。
  2. 第2个人抢到金额的随机范围就小得多了,只有[0.01,49.99]元,在正常的情况下,抢到金额的中位数是25元。假设第2个人随机抢到了25元,那么剩余金额是25元。
  3. 第3个人抢到金额的随机范围就更小了,只有[0,24.99]元,按中位数可以抢到12.5元。
  4. 以此类推,红包的随机范围将会越来越小,不符合红包拆分的金额尽可能分布均衡的需求。。。

二倍均值法

把每次随机金额的上限定为剩余人均金额的2倍。

红包金额为m元
剩余人数为n
每次抢到的金额 = 随机区间 [0.01,m /n × 2 - 0.01]元

保证了每一次抢到金额随机范围的均值是相等的,不会因为抢红包的先后顺序而造成不公平。

  1. 第1次随机的金额有一半概率超过20元,使得后面的随机金额上限不足39.99元;
  2. 第1次随机的金额同样也有一半的概率小于20元,使得后面的随机金额上限超过39.99元。
  3. 因此从整体来看,第2次随机的平均范围仍然是[0.01,39.99]元。

JAVA实现

    /**
     * 分配红包的金额
     * @param totalAmount     总金额(以分为单位)
     * @param totalPeopleNum  总人数
     * @return
     */
    public static List<Integer> divideRedPackage(Integer totalAmount,Integer totalPeopleNum){
        List<Integer> amountList = new ArrayList<Integer>();//存储分配的不同红包大小的数值
        Integer restAmount = totalAmount;
        Integer restpeopleNum = totalPeopleNum;
        Random random = new Random();
        //最后一个人不用随机分配了,之间差值
        for (int i=0;i<totalPeopleNum-1;i++){
            //随机范围:[1,剩余人均金额的2倍-1] 分
            //+1d的原因是:random.nextInt随机返回一个值在[0,num)的int类型的整数,包括0不包括num
            //random.nextInt+1的范围是[1,num+1)也就是[1,num]
            //就满足了随机区间: [1 , m /n × 2 - 1]分
            int amount = random.nextInt((restAmount/restpeopleNum)*2-1)+1;
            restAmount = restAmount-amount;
            restpeopleNum--;
            amountList.add(amount);
        }
        amountList.add(restAmount);
        return amountList;
    }

测试方法:

    public static void main(String[] args) {
        List<Integer> amountList = divideRedPackage(1000,10);
        for (Integer e:amountList){
            System.out.print(e+"  ");
        }
        System.out.println();
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

局限性
除最后一次外,其他每次抢到的金额都要小于剩余人均金额的2倍,并不是完全自由地随机抢红包。(随机数值的上限被限制死了

线段切割法

把红包总金额想象成一条很长的线段,而每个人抢到的金额,则是这条主线段所拆分出的若干子线段。

确定每一条子线段的长度

由“切割点”来决定。
当n个人一起抢红包时,就需要确定n-1个切割点。

当所有切割点确定以后,子线段的长度也随之确定。此时红包的拆分金额,就等同于每个子线段的长度

当n个人一起抢总金额为m的红包时,我们需要做n-1次随机运算,以此确定n-1个切割点。
随机的范围区间是[1, m-1]。
开始1和结束是m-1的原因是最少分配1分钱(这里1表示一分)
[0,1]一段,[m-1,m]一段(最小的情况)

需要考虑的问题:

  1. 当随机切割点出现重复时,如何处理。
  2. 如何尽可能降低时间复杂度和空间复杂度。

JAVA实现

HashMap和HashSet区别HashSet存取值

/**
     * 拆分红包V2
     * @param totalAmount  总金额(以分为单位)
     * @param totalPeopleNum  总人数
     */
    public static List<Integer> divideRedPackageV2(Integer totalAmount, Integer totalPeopleNum){
        List<Integer> amountList = new ArrayList<Integer>();
        Set<Integer> segments = new HashSet<Integer>();
        Random random = new Random();
        for(int i = 0; i< totalPeopleNum-1; i++){
            //切割的位置segment,随机的范围区间是[1, m-1]
            int segment =  random.nextInt(totalAmount-2) + 1;
            //delta == 1
            int delta = random.nextInt(1)==0 ? 1 : -1;
            //这是异常的情况
            // segments.contains(segment) ==true 表示切割位置重复
            //segment == 0,切割位置不正确
            while(segments.contains(segment) || segment == 0){
                //加上1位,用来解决以上俩个问题。
                //%totalAmount是解决超过线段长度的情况。
                segment = (segment+delta)%totalAmount;
            }
            segments.add(segment);
        }

        //依据切割的段来划分 钱数
        //从HashSet取值
        //Collections.sort排序方法,把切割位置从小到大排序。
        List<Integer> segmentList = new ArrayList<Integer>(segments);
        Collections.sort(segmentList);
        for(int i=0; i<segmentList.size(); i++){
            Integer amount;
            if(i==0){
                amount = segmentList.get(0);
            }else {
                amount = segmentList.get(i) - segmentList.get(i-1) ;
            }
            amountList.add(amount);
        }
        amountList.add(totalAmount - segmentList.get(segmentList.size()-1));

        return amountList;
    }

测试方法:

    public static void main(String[] args) {
        List<Integer> amountList = divideRedPackageV2(1000,10);
        for (Integer e:amountList){
            System.out.print(e+"  ");
        }
        System.out.println();
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

保证了每次划分都是随机,并且概率相同,并且没有最大限制。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构---红包分配算法 的相关文章

  • 从 java sdk 向对等方发送提案时出现访问被拒绝错误

    我正在尝试使用以下代码查询区块链并收到访问被拒绝错误 我也遇到同样的错误sendTransactionProposal方法也是如此 UserContext adminUserContext RegisterEnrollUser regist
  • JDK 文档是语言规范的一部分吗?

    只有一名官员Java语言规范 https docs oracle com javase specs jls se8 html index html所有 Java 实现都必须遵守它 API文档怎么样 所有Java实现都需要遵守吗这个版本 ht
  • 如何将 javax.persistence.Column 定义为 Unsigned TINYINT?

    我正在基于 MySQL 数据库中的现有表创建 Java 持久性实体 Bean 使用 NetBeans IDE 8 0 1 我在这个表中遇到了一个字段 其类型为 无符号 TINYINT 3 我发现可以执行以下操作将列的类型定义为 unsign
  • 使用 Ant 将非代码资源添加到 jar 文件

    我正在将 java 应用程序打包成 jar 文件 我正在使用 ant 和 eclipse 我实际上需要在 jar 中直接在根文件夹下包含几个单独的非代码文件 xml 和 txt 文件 而不是与代码位于同一位置 我正在尝试使用includes
  • JVisualVM/JConsole 中的 System.gc() 与 GC 按钮

    我目前正在测试处理 XML 模式的概念验证原型 并围绕一个非常消耗内存的树自动机外部库 我已经获得了源代码 构建 我想绘制 真实峰值 堆 随着模式大小的增加 不同运行的内存消耗 使用的指标符合我的目的并且不会影响问题 或者至少是它的合理近似
  • 在 Wildfly 中与 war 部署共享 util jar 文件

    假设我有一个名为 util jar 的 jar 文件 该 jar 文件主要包含 JPA 实体和一些 util 类 无 EJB 如何使这个 jar 可用于 Wildfly 中部署的所有 war 无需将 jar 放置在 war 的 WEB IN
  • Integer.parseInt("0x1F60A") 以 NumberformatException 结束

    我尝试从数据库中获取长字符串内的表情符号代码 格式如下 0x1F60A 所以我可以访问代码 但它将是String 起初 我尝试通过执行以下操作来转换变量tv setText beforeEmo getEmijoByUnicode int e
  • Kotlin 未解决的参考:CLI 上 gradle 的 println

    放一个printlnkotlin 函数返回之前的语句会崩溃 堆栈跟踪 thufir dur NetBeansProjects kotlin thufir dur NetBeansProjects kotlin gradle clean bu
  • 如何使用 Hibernate (EntityManager) 或 JPA 调用 Oracle 函数或过程

    我有一个返回 sys refcursor 的 Oracle 函数 当我使用 Hibernate 调用该函数时 出现以下异常 Hibernate call my function org hibernate exception Generic
  • 使用 Guice 优化注册表

    你好 今天思考了一种优化 有一些疑问 语境 我正在使用 Guice 2 进行 Java 开发 在我的网络应用程序中 我有一个转换器注册表 可以即时转换为某种类型 转换器描述如下 public class StringToBoolean im
  • 生成的序列以 1 开头,而不是注释中设置的 1000

    我想请求一些有关 Hibernate 创建的数据库序列的帮助 我有这个注释 下面的代码 在我的实体类中 以便为合作伙伴表提供单独的序列 我希望序列以 1000 开头 因为我在部署期间使用 import sql 将测试数据插入数据库 并且我希
  • 在另一个模块中使用自定义 gradle 插件模块

    我正在开发一个自定义插件 我希望能够在稍后阶段将其部署到存储库 因此我为其创建了一个独立的模块 在对其进行任何正式的 TDD 之前 我想手动进行某些探索性测试 因此 我创建了一个使用给定插件的演示模块 到目前为止 我发现执行此操作的唯一方法
  • 内部存储的安全性如何?

    我需要的 对于 Android 我需要永久保存数据 但也能够编辑 并且显然是读取 它 用户不应访问此数据 它可以包含诸如高分之类的内容 用户不得对其进行编辑 我的问题 我会 并且已经 使用过Internal Storage 但我不确定它实际
  • 使用布尔值进行冒泡排序以确定数组是否已排序

    我有以下用于冒泡排序的代码 但它根本不排序 如果我删除布尔值那么它工作正常 我知道 由于我的 a 0 小于所有其他元素 因此没有执行交换 任何人都可以帮助我解决这个问题 package com sample public class Bub
  • “无法实例化活动”错误

    我的一个 Android 应用程序拥有大约 100 000 个用户 每周大约 10 次 我会通过 Google 的市场工具向我报告以下异常情况 java lang RuntimeException Unable to instantiate
  • 使用按钮作为列表的渲染器

    我想使用一个更复杂的渲染器 其中包含列表的多个组件 更准确地说 类似于this https stackoverflow com questions 10840498 java swing 1 6 textinput like firefox
  • OpenCSV:将嵌套 Bean 映射到 CSV 文件

    我正在尝试将 bean 映射到 CSV 文件 但问题是我的 bean 具有其他嵌套 bean 作为属性 所发生的情况是 OpenCSV 遍历属性找到一个 bean 然后进入其中并映射该 bean 内的所有数据 如果找到另一个 bean 它就
  • 如何重新启动死线程? [复制]

    这个问题在这里已经有答案了 有哪些不同的可能性可以带来死线程回到可运行状态 如果您查看线程生命周期图像 就会发现一旦线程终止 您就无法返回到新位置 So 没有办法将死线程恢复到可运行状态 相反 您应该创建一个新的 Thread 实例
  • 泛型、数组和 ClassCastException

    我想这里一定发生了一些我不知道的微妙事情 考虑以下 public class Foo
  • 在java中使用多个bufferedImage

    我正在 java 小程序中制作游戏 并且正在尝试优化我的代码以减少闪烁 我已经实现了双缓冲 因此我尝试使用另一个 BufferedImage 来存储不改变的游戏背景元素的图片 这是我的代码的相关部分 public class QuizApp

随机推荐

  • 12帧跑步动画分解图_今天给大家分享一个跑步动画教程和注意事项!希望有所帮助!...

    跑步的动画的制作 一 跑步的基本原理 前面介绍了走路的动画的制作 跑步的制作方式和走路的方式是一样的 但是我们怎样来区别这两个动作的不同呢 虽然跑步在日常生活中经常看见 但是我们可能从来没有仔细的分析每一个动作 现在我们再来简单的说一下走路
  • upload labs第二关

    从上往下 首先定义两个变量 其中一个为空 在点击提交按钮后 前提文件路径可以找到 开始看文件类型是否为jpeg png gif格式 is upload false msg null if isset POST submit if file
  • Docker搭建zookeeper

    问题背景 前言 本文参考自 docker compose快速搭建Zookeeper集群 熬到凌晨三点多验证部署成功 网上有很多文章已经无法正确部署了 因为有些东西版本升级了 版本跟不上就会报错 还有一种更加详细更加全面的部署方式 Docke
  • 新人如何快速高效的学习Java?

    如果是新人 不想通过培训班 想学java 那么我可以很认真的告诉你 如果你是因为兴趣学学 那么你怎么学都可以 建议你找一些零基础入门的视频来学习 先看一遍 认识一下Java是个什么东西 如果是想转行学习 靠这个来工作 那么你就要好好的制定一
  • 一台计算机要两个内网,局域网如何在一台电脑上设置两个IP地址

    由于工作原因 有时需要连接两个局域网 除了频繁地更换不同局域网的网线 还要不停地设置不同局域网的IP地址 真是很麻烦 下面是学习啦小编收集整理的局域网如何在一台电脑上设置两个IP地址 希望对大家有帮助 局域网在一台电脑上设置两个IP地址的方
  • STM32F4单片机ADC采样及ARM-DSP库的FFT

    模拟信号经过ADC采样后变成数字信号 数字信号可以进行FFT运算 在频域中更容易分析信号的特征 本文将介绍如何用STM32F4的进行ADC采样 并利用ARMDSP库里的FFT算法对ADC采样值进行快速傅里叶变换 我使用的是STM32F407
  • CUDA编程中内存管理机制

    GPU设备端存储器的主要分类和特点 大小 全局 Global 和纹理 Texture 内存 大小受RAM大小的限制 本地 local 内存 每个线程限制在16KB
  • windows平台中使用vscode远程连接linux进行c++开发配置教程(内容详细适合小白)-2021-3-30

    文章目录 一 简要介绍 二 软件安装步骤 1 linux系统安装 2 vscode安装 3 ssh安装 4 配置Remote SSH 5 安装远程插件 6 简单小测试 三 配置vscode开发环境 1 默认设置 用户设置 远程设置和工作区设
  • Qt 开发环境搭建

    Qt开发环境搭建 Qt下载 Qt安装 Windows平台 离线安装 在线安装 Qt安装目录 VS2019搭建Qt开发环境 安装扩展插件 Qt VS Tools Qt Versions配置 问题 VS2019双击编辑UI时闪退 qt显示中文乱
  • 区块链物品溯源系统

    文章目录 前言 一 区块链有哪些特点 二 区块链能给品牌或者行业带来什么 1 信任度 2 小程序展示 总结 前言 区块链是一个典型的分布式协同系统 多方共同维护一个不断增长的分布式数据记录 这些数据通过密码学技术保护内容和时序 使得任何一方
  • Qt multiple definition of (function)

    前景 做项目代码优化 将原来的代码按简单工厂模式进行重新组合编写 对整个模块的文件夹进行分类 归纳 中途 出现这一问题 问题详述 某一类中的全部函数都有error multiple definition of function name 解
  • Linux 下刷 TWRP

    安装 adb 和 fastboot apt install android tools adb android tools fastboot 下载需要的 TWRP https dl twrp me flo 开机状态下进入 bootloade
  • async_await用法

    async作为修饰关键字修饰在函数前 表示该函数是一个异步函数 await的使用必须有async关键字 await等待的必须是一个promise对象 async返回的是一个promise对象 asyn function A return 星
  • pthread_cond_destroy()函数的使用

    NAME pthread cond destroy pthread cond init destroy and initialize condition variables SYNOPSIS THR include
  • 像数组一样使用NodeList:一个对象组合的有效用法

    场景 我是用querySelectorAll 查询了一些标记 并收到了一个NodeList响应 问题 节点列表类似于数组 比如 他们都有一个长度属性 它们都在括号中的索引访问它们的属性或者子元素 NodeList 0 尝试使用 map fi
  • 最小二乘法–高斯牛顿迭代法

    最小二乘法 高斯牛顿迭代法 本文将详解最小二乘法的非线性拟合 高斯牛顿迭代法 1 原理 高斯 牛顿迭代法的基本思想是使用泰勒级数展开式去近似地代替非线性回归模型 然后通过多次迭代 多次修正回归系数 使回归系数不断逼近非线性回归模型的最佳回归
  • ELK收集docker日志

    转载来源 ELK收集docker日志 1 安装docker 安装依赖 yum install y yum utils device mapper persistent data lvm2 添加软件源 yum config manager a
  • 【简单】228. 汇总区间

    原题链接 https leetcode cn problems summary ranges description 228 汇总区间 给定一个 无重复元素 的 有序 整数数组 nums 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围
  • CVPR 2021 Object Detection

    一 关于3D有26篇 3DIoUMatch Leveraging IoU Prediction for Semi Supervised 3D Object Detection ST3D Self Training for Unsupervi
  • 数据结构---红包分配算法

    红包分配算法 错误解法 二倍均值法 JAVA实现 线段切割法 确定每一条子线段的长度 JAVA实现 问题如下 所有人抢到的金额之和要等于红包金额 不能多也不能少 每个人至少抢到1分钱 要保证红包拆分的金额尽可能分布均衡 不要出现两极分化太严