实现拼手气红包算法,有以下几个需要注意的地方:

  1. 抢红包的期望收益应与先后顺序无关
  2. 保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比如区块链货币或者积分,需要自定义一个最小金额。
  3. 所有抢红包的人领取的子红包的金额之和加起来,等于发红包的人发出的总红包的金额。

下面实现的方式是一次生成所有的子红包,让用户按顺序领取。也可以每领取一个生成一个,两种方式性能上各有优劣。

代码如下:

/**

* 拼手气红包算法

* @param totalAmount 红包总金额

* @param size 领取人数

* @param scale 红包金额需要保留的小数位数

* @param minAmount 单个红包的最小金额

*/

private void randomHandOutAlgorithm(BigDecimal totalAmount, Integer size

, Integer scale, BigDecimal minAmount) {

//剩余红包金额

BigDecimal remainAmount = totalAmount.setScale(scale, BigDecimal.ROUND_DOWN);

//剩余红包个数

Integer remainSize = size;

for (int i = 1; i < size; i++) {

//前n-1个红包的金额,用随机算法

BigDecimal random = BigDecimal.valueOf(Math.random());

BigDecimal halfRemainSize = BigDecimal.valueOf(remainSize).divide(new BigDecimal(2), BigDecimal.ROUND_UP);

//计算单次红包的最大值,该算法也是微信的红包算法,可以保证抢红包的期望收益应与先后顺序无关,但后抢红包的方差更大,因此手气最佳更可能在后抢的人中诞生

BigDecimal max1 = remainAmount.divide(halfRemainSize, BigDecimal.ROUND_DOWN);

//同时,最大值需要保证,减去该红包后,剩下的红包足以满足剩余人数的最小金额

BigDecimal minRemainAmount = minAmount.multiply(BigDecimal.valueOf(remainSize - 1)).setScale(scale, BigDecimal.ROUND_DOWN);

BigDecimal max2 = remainAmount.subtract(minRemainAmount);

//最终,单次红包的最大值等于两个最大值中较小的一个

BigDecimal max = (max1.compareTo(max2) < 0) ? max1 : max2;

BigDecimal amount = random.multiply(max).setScale(scale, BigDecimal.ROUND_DOWN);

//每个红包的数额不能小于预设的最小金额

if (amount.compareTo(minAmount) < 0) {

amount = minAmount;

}

remainAmount = remainAmount.subtract(amount).setScale(scale, BigDecimal.ROUND_DOWN);

remainSize = remainSize - 1;

}

//最后一个红包,金额等于剩余金额

BigDecimal amount = remainAmount;

}

最后,未领取的金额需要退回给发红包的用户。写一个定时任务,将未领取的子红包退回即可。

如果在用户每次领取红包的时候生成一个子红包,算法也是一样的,只是每领取一次子红包后,都要更新总红包的余额和剩余数量,然后在退回过期红包时,将总红包的余额退回给发红包的用户即可。

JAVA实现拼手气红包算法的更多相关文章

  1. php实现微信拼手气红包

    $result = sendHB(3, 5); echo '<pre>'; var_export($result); echo array_sum($result); /** * 拼手气红 ...

  2. java 实现仿照微信抢红包算法,实测结果基本和微信吻合,附demo

    实现拼手气红包算法,有以下几个需要注意的地方: 抢红包的期望收益应与先后顺序无关 保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比如 ...

  3. 微信红包算法TEST

    1.基本算法 设定总金额为10元,有N个人随机领取:N=1 则红包金额=X元: N=2 为保证第二个红包可以正常发出,第一个红包金额=0.01至9.99之间的某个随机数 第二个红包=10-第一个红包金 ...

  4. Java判断回文数算法简单实现

    好久没写java的代码了, 今天闲来无事写段java的代码,算是为新的一年磨磨刀,开个头,算法是Java判断回文数算法简单实现,基本思想是利用字符串对应位置比较,如果所有可能位置都满足要求,则输入的是 ...

  5. Java中常用的查找算法——顺序查找和二分查找

    Java中常用的查找算法——顺序查找和二分查找 神话丿小王子的博客 一.顺序查找: a) 原理:顺序查找就是按顺序从头到尾依次往下查找,找到数据,则提前结束查找,找不到便一直查找下去,直到数据最后一位 ...

  6. 深入理解java虚拟机【垃圾回收算法】

    Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...

  7. Java学习之二分查找算法

    好久没写算法了.只记得递归方法..结果测试下爆栈了. 思路就是取范围的中间点,判断是不是要找的值,是就输出,不是就与范围的两个临界值比较大小,不断更新临界值直到找到为止,给定的集合一定是有序的. 自己 ...

  8. 如何用70行Java代码实现深度神经网络算法

    http://www.tuicool.com/articles/MfYjQfV 如何用70行Java代码实现深度神经网络算法 时间 2016-02-18 10:46:17  ITeye 原文  htt ...

  9. Java面试常考------------------------垃圾收集算法

    对于Java系学生而言,Java虚拟机中的垃圾收集算法是一个很重要的面试考点. 常用的垃圾收集算法主要可划分为以下三类: 1. 标记-清除算法 标记清除算法是一种比较简单的方法,直接标记内存中待回收的 ...

随机推荐

  1. redis: 事务管理(九)

    redis的事务 不保证原子性 三个步骤:开启事务.命令入队.执行事务 开启事务:multi 执行事务:exec 127.0.0.1:6379> multi #开启事务 OK 127.0.0.1 ...

  2. 痞子衡嵌入式:大话双核i.MXRT1170之Cortex-M7与Cortex-M4互相激活之道

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M7与Cortex-M4内核互相激活的方法. 痞子衡最近在深耕i.MXRT1170这颗划时代的 ...

  3. thinkphp5和nginx不得不说的故事

    由于之前学习用的都是apsche,所以对ngnix一窍不通,在这里写给正在学习的同行,希望可以帮助到你们: 如果你不会用apache部署tp5的可以查看我之前发布的文章,里面有提到 phpstudy ...

  4. PHP使用token防止表单重复提交的方法

    本文实例讲述了PHP使用token防止表单重复提交的方法.分享给大家供大家参考,具体如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 ...

  5. 基于Atlas实现mysql读写分离

    一.实验环境 主机名IP地址 master192.168.200.111 slave192.168.200.112 atlas192.168.200.113 主从复制不再赘述,链接地址:授权Atlas ...

  6. nginx与keepalived实现高可用+Apache实现负载均衡

    nginx与keepalived实现高可用 本实验使用了四台虚拟机 两台需要安装nginx及keepalived 两台安装Apache nginx可以源码安装也可以用yum安装nginx yum安装n ...

  7. Linux网络服务第一章Linux网络基础设置

    1.笔记 systenctl restart network:重启网卡网络服务 bash:刷新主机名称 netstat:查看网络状态 route -n:不做地址解析 mii-tool eno16777 ...

  8. hdu_2570 迷障 贪心

    迷瘴 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...

  9. CHIL-SQL-DELETE 语句

    DELETE 语句 DELETE 语句用于删除表中的行. 语法 DELETE FROM 表名称 WHERE 列名称 = 值 Person: LastName FirstName Address Cit ...

  10. 老男孩教育每日一题-2017年3月29日-使用ifconfig取出网卡eth0的ip地址-看看你有多少方法...

    方法1:sed命令 [root@oldboyedu ~]# ifconfig eth0 |sed -n '2p' |sed's#^.*addr:##g'|sed 's#  B.*$##g' 10.0. ...