关于随机红包抽奖算法

Posted jolins

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于随机红包抽奖算法相关的知识,希望对你有一定的参考价值。

场景:

  生成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

 

以上是关于关于随机红包抽奖算法的主要内容,如果未能解决你的问题,请参考以下文章

关于MEET大会直播抽奖后续红包发放的说明

数据结构算法入门--链表(文末有红包抽奖)

抽奖算法-指定概率的随机

PHP抽奖小程序/微信红包封面抽奖小程序/抽奖小程序开源源码

java版抽奖算法

java版抽奖算法