场景限制说明

  • 所有人抢到的金额之和等于红包总额。
  • 每个人最少抢到 0.01 元。
  • 保证每个人抢到的金额机率相等。(由生成红包随机金额算法决定)

使用方法

1
2
3
4
5
6
7
public static void main(String[] args) {
System.out.println(RedPacketUtil.divideRedPacket(10, 10));
System.out.println(RedPacketUtil.divideRedPacket(10, 10));
System.out.println(RedPacketUtil.divideRedPacket(10, 10));
System.out.println(RedPacketUtil.divideRedPacket(10, 10));
System.out.println(RedPacketUtil.divideRedPacket(10, 10));
}

生成随机红包集合

1
2
3
4
5
[1.06, 1.87, 1.55, 1.14, 1, 1.11, 0.44, 0.95, 0.64, 0.24]
[0.92, 1.09, 1.18, 1.6, 0.9, 1.09, 0.57, 0.29, 0.91, 1.45]
[1.82, 1.72, 0.68, 1.41, 1.05, 0.56, 0.61, 1.27, 0.04, 0.84]
[1.62, 1.02, 1.39, 0.4, 0.01, 0.77, 2.17, 0.73, 0.52, 1.37]
[1.75, 0.25, 0.27, 1.05, 0.24, 1.32, 0.61, 2.67, 1.08, 0.76]

核心算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* Created with IntelliJ IDEA.
* DateTime: 2020/5/22 14:30
* 二倍均值法 -- 红包案例
*
* @author muycode
*/
public class RedPacketUtil {

/**
* 红包生成算法
*
* @param amountMax 红包总金额 以元为单位
* @param peopleMax 总人数
* @return
*/
public static List<BigDecimal> divideRedPacket(double amountMax, Integer peopleMax) {
// 最终分配的金额列表
List<BigDecimal> amountList = new ArrayList<>();

// 把元换算成分
Integer divideAmount = (int) (amountMax * 100);

// 判断金额、人数的合法性
if (divideAmount < peopleMax || divideAmount <= 0 || peopleMax <= 0) {
return amountList;
}

// 初始化金额为红包的总金额
Integer resetAmount = divideAmount;
// 初始化人数为红包的总人数
Integer resetPeople = peopleMax;

Random random = new Random();
for (int i = 0; i < peopleMax - 1; i++) {
int amount = random.nextInt(resetAmount / resetPeople * 2 - 1) + 1;
// 更新剩余总金额
resetAmount -= amount;
// 更新剩余总人数
resetPeople--;
amountList.add(BigDecimal.valueOf(amount).divide(BigDecimal.valueOf(100)));
}
amountList.add(BigDecimal.valueOf(resetAmount).divide(BigDecimal.valueOf(100)));
return amountList;
}
}

参考文章:

《分布式中间件技术实战(Java 版)》