码迷,mamicode.com
首页 > 编程语言 > 详细

关于随机红包抽奖算法

时间:2019-09-17 18:54:56      阅读:134      评论:0      收藏:0      [点我收藏+]

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

 

关于随机红包抽奖算法

标签:部分   之间   防止   param   场景   方法   col   integer   lis   

原文地址:https://www.cnblogs.com/jolins/p/11536102.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!