JAVA實現拼手氣紅包算法


實現拼手氣紅包算法,有以下幾個需要注意的地方:

  1. 搶紅包的期望收益應與先后順序無關
  2. 保證每個用戶至少能搶到一個預設的最小金額,人民幣紅包設置的最小金額一般是0.01元,如果需要發其他貨幣類型的紅包,比如區塊鏈貨幣或者積分,需要自定義一個最小金額。
  3. 所有搶紅包的人領取的子紅包的金額之和加起來,等於發紅包的人發出的總紅包的金額。

下面實現的方式是一次生成所有的子紅包,讓用戶按順序領取。也可以每領取一個生成一個,兩種方式性能上各有優劣。

代碼如下:

/**

* 拼手氣紅包算法

* @param totalAmount 紅包總金額

* @param size 領取人數

* @param scale 紅包金額需要保留的小數位數

* @param minAmount 單個紅包的最小金額

*/

private void randomHandOutAlgorithm(BigDecimal totalAmount, Integer size

, Integer scale, BigDecimal minAmount) {

//剩余紅包金額

BigDecimal remainAmount = totalAmount.setScale(scale, BigDecimal.ROUND_DOWN);

//剩余紅包個數

Integer remainSize = size;

for (int i = 1; i < size; i++) {

//前n-1個紅包的金額,用隨機算法

BigDecimal random = BigDecimal.valueOf(Math.random());

BigDecimal halfRemainSize = BigDecimal.valueOf(remainSize).divide(new BigDecimal(2), BigDecimal.ROUND_UP);

//計算單次紅包的最大值,該算法也是微信的紅包算法,可以保證搶紅包的期望收益應與先后順序無關,但后搶紅包的方差更大,因此手氣最佳更可能在后搶的人中誕生

BigDecimal max1 = remainAmount.divide(halfRemainSize, BigDecimal.ROUND_DOWN);

//同時,最大值需要保證,減去該紅包后,剩下的紅包足以滿足剩余人數的最小金額

BigDecimal minRemainAmount = minAmount.multiply(BigDecimal.valueOf(remainSize - 1)).setScale(scale, BigDecimal.ROUND_DOWN);

BigDecimal max2 = remainAmount.subtract(minRemainAmount);

//最終,單次紅包的最大值等於兩個最大值中較小的一個

BigDecimal max = (max1.compareTo(max2) < 0) ? max1 : max2;

BigDecimal amount = random.multiply(max).setScale(scale, BigDecimal.ROUND_DOWN);

//每個紅包的數額不能小於預設的最小金額

if (amount.compareTo(minAmount) < 0) {

amount = minAmount;

}

remainAmount = remainAmount.subtract(amount).setScale(scale, BigDecimal.ROUND_DOWN);

remainSize = remainSize - 1;

}

//最后一個紅包,金額等於剩余金額

BigDecimal amount = remainAmount;

}

最后,未領取的金額需要退回給發紅包的用戶。寫一個定時任務,將未領取的子紅包退回即可。

 

如果在用戶每次領取紅包的時候生成一個子紅包,算法也是一樣的,只是每領取一次子紅包后,都要更新總紅包的余額和剩余數量,然后在退回過期紅包時,將總紅包的余額退回給發紅包的用戶即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM