关于随机红包抽奖算法

2020-12-13 13:44

阅读:593

标签:部分   之间   防止   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


评论


亲,登录后才可以留言!