• 关于微信手气红包算法的探讨


    关于微信手气红包算法的探讨

    前言

    这大过年的,长辈家人朋友发的红包抢到手软,嘿嘿嘿。昨晚,和一个朋友出去浪,刚好两人现在就读专业相同,不知不觉间就谈到了微信红包的算法。今天闲来无事,就简单的做了一下记录。

    第一种

    这个是最简单的实现,就是先给每个红包分配0.01(确保大家都有),然后各个红包轮流产生一个随机数(不得大于当前总金额)并从总金额中取出相应的数,最后一个红包不管如何,全盘接收总金额。
    贴 java 代码:

    ```java
        /**
         * 最简单的分配方法,单位全部统一为 分
         * @param number 红包总数
         * @param money 金额总数
         */
        public void redPacket1 (int number, int money){
            int minCount = 1;   //最低金额
            int moneyCount = money*100 - minCount*number;   //分配给各个红包 0.01后可分配金额
            Random random = new Random();
            float[] array = new float[number];  //储存红包金额的数组
            StringBuffer arrayStr = new StringBuffer("");   //为了方便显示
            //为前 number-1 个红包分配金额
            for (int i=0; i<number-1; i++){
                try {
                    array[i] = (minCount+random.nextInt(moneyCount)) ;
                } catch (IllegalArgumentException e){   //防止 moneyCount 为0
                    array[i] = minCount ;
                }
                if (moneyCount!=0)  //可分配金额可以继续分配
                    moneyCount -= array[i];
                arrayStr.append(String.valueOf((double) array[i]/100) + " ");
            }
            array[number-1] = moneyCount+minCount;
            arrayStr.append(String.valueOf((double) array[number-1]/100) + " ");
            System.out.println(arrayStr);   //将各个红包金额打印出来
        }
    

    测试贴图:
    假设有个20块的手气红包,分配为10个,(不考虑边界数据的情况)
    这里写图片描述

    从结果中可以很清楚看出它的缺陷:
    * 波动太大;
    * 先抢的人往往会占据大部分红包。

    不过,我觉得这种算法还是存在的,一般适应于大红包少人的情况:


    这里写图片描述
    我怀疑我抢了个假红包!!!

    第二种

    第二种主要就是给随机数增加一个上限,我朋友说可以使用总金额平均数来控制波动,我觉得可以改为使用平均数的某个倍数(我限制为1.0-2.9之间波动)。毕竟,抢红包体现出欧皇气质也不失为一种极大的乐趣!
    同时,因为 java 中的 Random() 是一个伪随机数,为了防止倍数与金额随机数的影响(程序猿癖好),我重新 new 了个对象和封装为方法使用。
    贴 java 代码:

     /**
         * 分配方法二,单位全部统一为 分
         * @param number 红包总数
         * @param money 金额总数
         */
        public void redPacket2(int number, int money){
            Random random = new Random();
            float times = (float)random.nextInt(20)/10 + 1; //获取一个倍数
            StringBuffer buffer = new StringBuffer();
            int minCount = 1;
            int moneyCount = money * 100;   //这次是金额总数
            int max = (int)(moneyCount*times/number);   //可分配最大值
            for(int i=0; i<number; i++){
                int packet = randomPacket(minCount, max, number-i, moneyCount);
                moneyCount -= packet;
                buffer.append(String.valueOf((double) packet/100) + " ");
            }
            buffer.append(" 倍数为:"+times);
            System.out.println(buffer);
        }
    

     封装的方法:

      /**
         * 分配一个红包
         * @param minCount
         * @param maxCount
         * @param number
         * @param money
         * @return
         */
        private int randomPacket(int minCount, int maxCount, int number, int money){
            Random random = new Random();
            if (number == 1) return money;  //最后一个红包
            if (minCount == maxCount) return minCount;  //最大随机数与最小随机数相同
            int max = maxCount>money ? money : maxCount;    //若倍数最大值大于现在的金额时,动态改变波动上限
            int packet = minCount;
            try {
                packet += random.nextInt(max-minCount);
            } catch (IllegalArgumentException e){   //还是可能出现 max-minCount 为 0 的情况
                packet += 0;
            }
            return packet;
        }
    

    测试贴图:
    假设有个20块的手气红包,分配为10个,(不考虑边界数据的情况)
    这里写图片描述
    这次许多数值就比较正常,但还是有缺陷的,我觉得微信红包出现 0.01 的概率比较大,但这种算法得出 0.01 的概率不是一般的小。Ps:100次测试中出现只出现了一次0.01。

    最后

    我自己觉得微信抢红包的算法肯定不止一种,应该是在某个金额和红包数时选择某种更具趣味性的算法。知乎上也有一个关于红包算法的讨论,也有许多可取之处。

  • 相关阅读:
    理解全虚拟、半虚拟以及硬件辅助的虚拟化
    使用PowerShell向SharePoint中写入数据
    Python的时间模块小结(转自:不懂真人)
    Windows下如何安装Python的第三方库
    Python的正则表达式笔记
    PG, Pool之间的一些数量关系
    Ceph与OpenStack的Nova相结合
    rbd命令
    rados命令
    ceph命令
  • 原文地址:https://www.cnblogs.com/MaxElephant/p/8108752.html
Copyright © 2020-2023  润新知