前言
说到抢红包,大家肯定是很熟悉了,尤其是微信抢红包,我们几乎天天都会接触。虽然每次抢到的红包金额有大有小,但是我们都深深的沉浸在抢红包的快乐中😄。不过话说回来,不知道各位小伙伴有没有思考过抢红包使用的是什么算法呢?是如何实现的呢?今天我们一探究竟...
抢红包
现在我们发放的红包无非就是两种形式:拼手气红包和固定金额红包。固定金额红包的个数可以是一个也可以是多个,而且每一个红包里的金额都是一样的,所以也就不需要使用过多的算法去计算红包金额,相对来说就简单一些;而拼手气红包就相对复杂一些了,它需要计算每个红包的金额,而且要保证每个红包尽量公平,这也就对算法的要求比较高了。通过查阅百度和咨询实现过抢红包功能的朋友,了解到现在使用频率比较高的算法就是二倍均值法,下面我们就使用二倍均值法来模拟实现抢红包功能👇
通过二倍均值法模拟抢红包
首先我们先看一下拼手气红包的功能要求:
- 所有红包累计金额等于红包总金额
- 每个红包金额不能小于0.01元,也就是说必须保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果是发放其他类型的红包(比如积分、其他类型货币等),则需要自定义一个最小金额
- 抢红包的期望收益应与先后顺序无关,即每个红包的金额大小和抢红包的先后顺序无关,保证红包尽量的公平
在实现上面的功能要求之前,我们还需要了解一下什么是二倍均值法👇
假设红包总金额是X,红包个数为Y,每个红包的最低金额是0.01元,那么每次抢到的红包金额的范围在 (0.01, (X/Y) *2) 之间。
咱们举个具体的例子,假如现在有10个人来抢一个金额为100元的红包,那么根据上面的公式可以得出,第一个人抢到的金额范围是在(0.01,20)之间,那么根据正态分布可以得知,第一个人抢到的金额应该是在10元左右,并且远小于10元和远大于10元的概率都会很低,这里咱们就先假设第一个人抢到了10元;这时候第二个人来抢红包了,红包中剩下90元,我们根据公式可以得出,第二个人抢到的红包金额范围也是(0.01,20)之间。以此类推,我们可以看出来每个人所抢到的红包金额都在10元左右,并且远小于10元和远大于10元的概率都会很低,这样就尽可能的保证了每个人抢到的金额都是相近的。
接下来我们来看看具体的代码👇
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;
/**
* 通过二倍均值法模拟微信抢红包
* @description: RedEnvelope
* @author: 庄霸.liziye
* @create: 2022-02-15 14:43
**/
public class RedEnvelope {
public static void main(String[] args) {
long startTime=System.currentTimeMillis();
//初始化测试场景,模拟四种情况:
//10人抢0.1元红包
//10人抢1元红包
//10人抢10元红包
//10人抢100元红包
BigDecimal[][] scene = {
{new BigDecimal("0.1"), new BigDecimal("10")},
{new BigDecimal("1"), new BigDecimal("10")},
{new BigDecimal("10"), new BigDecimal("10")},
{new BigDecimal("100"), new BigDecimal("10")}
};
//设置每个红包的最低金额为0.01元
BigDecimal min &