实现抢红包算法?如此简单
發出一個固定金額的紅包,由若干個人來搶,需要滿足哪些規則?
1.所有人搶到金額之和等于紅包金額,不能超過,也不能少于。
2.每個人至少搶到一分錢。
3.要保證所有人搶到金額的幾率相等。
小灰的思路是什么樣呢?
每次搶到的金額 = 隨機區間?( 0,? 剩余金額 )
為什么這么說呢?讓我們看一個栗子:
假設有10個人,紅包總額100元。
第一個人的隨機范圍是(0,100元),平均可以搶到50元。
假設第一個人隨機到50元,那么剩余金額是100-50 = 50 元。
第二個人的隨機范圍是?(0, 50元),平均可以搶到25元。
假設第二個人隨機到25元,那么剩余金額是50-25 = 25 元。
第三個人的隨機范圍是?(0, 25元),平均可以搶到12.5元。
以此類推,每一次隨機范圍越來越小。
方法1:二倍均值法
剩余紅包金額為M,剩余人數為N,那么有如下公式:
每次搶到的金額 = 隨機區間?(0, M / N X 2)
這個公式,保證了每次隨機金額的平均值是相等的,不會因為搶紅包的先后順序而造成不公平。
舉個栗子:
假設有10個人,紅包總額100元。
100/10X2 = 20, 所以第一個人的隨機范圍是(0,20 ),平均可以搶到10元。
假設第一個人隨機到10元,那么剩余金額是100-10 = 90 元。
90/9X2 = 20, 所以第二個人的隨機范圍同樣是(0,20 ),平均可以搶到10元。
假設第二個人隨機到10元,那么剩余金額是90-10 = 80 元。
80/8X2 = 20, 所以第三個人的隨機范圍同樣是(0,20 ),平均可以搶到10元。
以此類推,每一次隨機范圍的均值是相等的。
//發紅包算法,金額參數以分為單位
public static List<Integer> divideRedPackage(Integer totalAmount, Integer totalPeopleNum){
? ?List<Integer> amountList = new ArrayList<Integer>();
? ?Integer restAmount = totalAmount;
? ?Integer restPeopleNum = totalPeopleNum;
? ?Random random = new Random();
? ?for(int i=0; i<totalPeopleNum-1; i++){
? ? ? ?//隨機范圍:[1,剩余人均金額的兩倍),左閉右開
? ? ? ?int amount = random.nextInt(restAmount / restPeopleNum * 2 - 1) + 1;
? ? ? ?restAmount -= amount;
? ? ? ?restPeopleNum --;
? ? ? ?amountList.add(amount);
? ?}
? ?amountList.add(restAmount);
? ?return amountList;
}
public static void main(String[] args){
? ?List<Integer> amountList = divideRedPackage(5000, 30);
? ?for(Integer amount : amountList){
? ? ? ?System.out.println("搶到金額:" + new BigDecimal(amount).divide(new BigDecimal(100)));
? ?}
}
程序輸出結果如下:
搶到金額:2.92
搶到金額:1.48
搶到金額:3.05
搶到金額:0.53
搶到金額:0.45
搶到金額:1.36
搶到金額:1.02
搶到金額:1.99
搶到金額:1.3
搶到金額:0.48
搶到金額:0.83
搶到金額:2.89
搶到金額:0.94
搶到金額:2.11
搶到金額:3.13
搶到金額:0.91
搶到金額:2.64
搶到金額:2.02
搶到金額:2.88
搶到金額:1.13
搶到金額:2.09
搶到金額:1.37
搶到金額:2.41
搶到金額:2.13
搶到金額:1.32
搶到金額:0.44
搶到金額:1.62
搶到金額:1.89
搶到金額:2.23
搶到金額:0.44
方法2:線段切割法
何謂線段切割法?我們可以把紅包總金額想象成一條很長的線段,而每個人搶到的金額,則是這條主線段所拆分出的若干子線段。
如何確定每一條子線段的長度呢?由“切割點”來決定。當N個人一起搶紅包的時候,就需要確定N-1個切割點。
因此,當N個人一起搶總金額為M的紅包時,我們需要做N-1次隨機運算,以此確定N-1個切割點。隨機的范圍區間是(1, M)。
當所有切割點確定以后,子線段的長度也隨之確定。這樣每個人來搶紅包的時候,只需要順次領取與子線段長度等價的紅包金額即可。
這就是線段切割法的思路。在這里需要注意以下兩點:
1.當隨機切割點出現重復,如何處理。
2.如何盡可能降低時間復雜度和空間復雜度。
—————END—————
總結
以上是生活随笔為你收集整理的实现抢红包算法?如此简单的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 创造与魔法怎么弄
- 下一篇: 微信小程序 详解 小程序支付