关于随机红包抽奖算法
标签:部分 之间 防止 param 场景 方法 col integer lis
场景:
生成10个随机红包, 奖池总金额10000, 最小500, 最大1000,奖池全部分配完。
分析:
第一想法简单, 直接生成500-1000之间的随机数,直接生成10个, 直接上代码
/**
*
* @param lst 生成的奖项列表
* @param minAmount 红包允许的最小金额
* @param maxAmount 红包允许的最大金额
* @param totalAmount 总奖池金额
* @param count 生成红包数量
*/public void generateRoundAmount(List lst, Integer minAmount, Integer maxAmount, Integer totalAmount, Integer count){
for (int i = 1; i ) {
//当前理论允许的最大金额, 保证后续每人持有最小
Integer tmpMax = totalAmount - minAmount * (count - i);
//前4成的最大金额,为理论最大金额的一半, 防止前面金额过大,后面全是1
tmpMax = i : tmpMax;
//当有传入最大金额,且小于当前理论最大金额, 则取最大金额,否则取理论最大金额
tmpMax = maxAmount != null && tmpMax > maxAmount ? maxAmount : tmpMax;
//当最后一个的时候,全部归其所有, 否则取随机数区间[min, max]
Integer tmpValue = i == count ? totalAmount : StringUtil.getRandomNumberBetween(minAmount, tmpMax);
lst.add(tmpValue);
//减去已抽取金额
totalAmount = totalAmount - tmpValue;
}
}
这种写法, 最后一个金额会出现问题,会有出现超过最大金额的可能性。
解决方法有两种:
第一种方法,判断最后一个金额大于maxAmount, 则重新运行,直到出现最后一个金额小于等于maxAmount即可。当然这种方法比较笨, 并不推荐。
第二中方法,就是剩余的金额, 继续在已经生成的奖项列表中分配(未超过最大金额的项)。
改造下方法
/**
*
* @param lst 生成的奖项列表
* @param minAmount 红包允许的最小金额
* @param maxAmount 红包允许的最大金额
* @param totalAmount 总奖池金额
* @param count 生成红包数量
*/public void generateRoundAmount(List lst, Integer minAmount, Integer maxAmount, Integer totalAmount, Integer count){
Integer remainingAmount = 0; //剩余金额, 默认0
for (int i = 1; i ) {
//当前理论允许的最大金额, 保证后续每人持有最小
Integer tmpMax = totalAmount - minAmount * (count - i);
//前4成的最大金额,为理论最大金额的一半, 防止前面金额过大,后面全是1
tmpMax = i : tmpMax;
//当有传入最大金额,且小于当前理论最大金额, 则取最大金额,否则取理论最大金额
tmpMax = maxAmount != null && tmpMax > maxAmount ? maxAmount : tmpMax;
if(i == count && maxAmount != null && totalAmount > maxAmount){
//最后一个红包数量大于最大允许金额, 计算出剩余金额
lst.add(maxAmount);
remainingAmount = totalAmount - maxAmount;
} else{
Integer tmpRandomInt = StringUtil.getRandomNumberBetween(minAmount, tmpMax);
lst.add(tmpRandomInt);
//奖池金额为总金额减去已抽取金额
totalAmount = totalAmount - tmpRandomInt;
}
}
//剩余金额大于0则继续分配
while(remainingAmount > 0){
addAmountToList(lst, maxAmount, remainingAmount);
}
}
/**
*
* @param lst
* @param maxAmount 允许最大金额
* @param totalAmount 可分配金额
*/
private void addAmountToList(List lst, Integer maxAmount, Integer totalAmount){
for (int i = 0; i ) {
if (totalAmount ){
break;
}
if (lst.get(i) //当列表中的金额小于最大金额时, 才分配
//临时最大允许金额
Integer tmpMax = maxAmount - lst.get(i) > totalAmount ? totalAmount : maxAmount - lst.get(i);
Integer tmpRandomInt = StringUtil.getRandomNumberBetween(1, tmpMax);
lst.set(i, lst.get(i) + tmpRandomInt);
totalAmount = totalAmount - tmpMax;
}
}
}
完工, 图方便, 金额直接用了Integer类型,可自行转换为decimal
关于随机红包抽奖算法
标签:部分 之间 防止 param 场景 方法 col integer lis
原文地址:https://www.cnblogs.com/jolins/p/11536102.html
评论