public class Problem_003_Grab_The_Red_Envelope {
/**
* 测试代码
*/
@Test
public void testMethods(){
Solution test1 = new Solution(new BigDecimal(50), 15);
for(int i = 0; i < 15; i++){
System.out.print(test1.nextRedEnvelope() + " ");
}
System.out.println();
Solution test2 = new Solution(new BigDecimal(0.2), 20);
for(int i = 0; i < 20; i++){
System.out.print(test2.nextRedEnvelope() + " ");
}
}
static class Solution{
/**
* 剩余金额
*/
private int restMoney;
/**
* 剩余人数
*/
private int restNum;
private Random rnd;
Solution(BigDecimal totalMoney, int totalNum){
if(totalMoney.doubleValue() <= 0 || totalNum < 1){
throw new IllegalArgumentException("红包总金额或者抢红包总人数存在异常!");
}
this.restMoney = totalMoney.multiply(new BigDecimal(100)).intValue();
this.restNum = totalNum;
if(this.restMoney < this.restNum){
throw new IllegalArgumentException("红包总金额不足每人1分钱!");
}
this.rnd = new Random();
}
/**
* 抢红包
*/
public synchronized BigDecimal nextRedEnvelope(){
if(this.restNum < 1){
throw new IllegalStateException("红包已经被抢光了!");
}
//1. 如果剩余人数为1,则直接返回
if(this.restNum == 1){
return this.format(this.restMoney);
}
//2. 开始抢红包
//2.1 计算剩余平均值
int averageMoney = this.restMoney / this.restNum;
//2.2 当前红包金额最大值:Min(averageMoney * 2, (restMoney - (restNum - 1))),目的是为了保障剩下的人至少可以抢到1分钱
int currentMaxMoney = Math.min((averageMoney * 2), (this.restMoney - (this.restNum - 1)));
//2.3 计算当前红包金额(最少可以抢到1分钱)
int money = Math.max(rnd.nextInt(currentMaxMoney), 1);
this.restMoney -= money;
this.restNum--;
return this.format(money);
}
/**
* 将抢到的红包转换回以元为单位的金额
*/
private BigDecimal format(int money){
return new BigDecimal(money).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
}
}
}