场景:
生成10个随机红包, 奖池总金额10000, 最小500, 最大1000,奖池全部分配完。
分析:
第一想法简单, 直接生成500-1000之间的随机数,直接生成10个, 直接上代码
/** * * @param lst 生成的奖项列表 * @param minAmount 红包允许的最小金额 * @param maxAmount 红包允许的最大金额 * @param totalAmount 总奖池金额 * @param count 生成红包数量 */public void generateRoundAmount(List<Integer> lst, Integer minAmount, Integer maxAmount, Integer totalAmount, Integer count){ for (int i = 1; i <= count ; i++) { //当前理论允许的最大金额, 保证后续每人持有最小 Integer tmpMax = totalAmount - minAmount * (count - i); //前4成的最大金额,为理论最大金额的一半, 防止前面金额过大,后面全是1 tmpMax = i <= Math.round(count*0.4) ? tmpMax/2 : 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<Integer> lst, Integer minAmount, Integer maxAmount, Integer totalAmount, Integer count){ Integer remainingAmount = 0; //剩余金额, 默认0 for (int i = 1; i <= count ; i++) { //当前理论允许的最大金额, 保证后续每人持有最小 Integer tmpMax = totalAmount - minAmount * (count - i); //前4成的最大金额,为理论最大金额的一半, 防止前面金额过大,后面全是1 tmpMax = i <= Math.round(count*0.4) ? tmpMax/2 : 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<Integer> lst, Integer maxAmount, Integer totalAmount){ for (int i = 0; i < lst.size(); i++) { if (totalAmount <= 0){ break; } if (lst.get(i) < maxAmount){ //当列表中的金额小于最大金额时, 才分配 //临时最大允许金额 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
原文地址:https://www.cnblogs.com/jolins/p/11536102.html
时间: 2024-11-10 09:20:09