關於微信手氣紅包算法的探討
阿新 • • 發佈:2017-12-25
繼續 ret 數據 max oat 般的 配方法 前言 閑來無事
關於微信手氣紅包算法的探討
前言
這大過年的,長輩家人朋友發的紅包搶到手軟,嘿嘿嘿。昨晚,和一個朋友出去浪,剛好兩人現在就讀專業相同,不知不覺間就談到了微信紅包的算法。今天閑來無事,就簡單的做了一下記錄。
第一種
這個是最簡單的實現,就是先給每個紅包分配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。
最後
我自己覺得微信搶紅包的算法肯定不止一種,應該是在某個金額和紅包數時選擇某種更具趣味性的算法。知乎上也有一個關於紅包算法的討論,也有許多可取之處。
關於微信手氣紅包算法的探討