前言
昨天是大年初一,怎麼說呢,因爲在讀大學, 沒有出來工作,所以昨晚也是陸陸續續有收到一些紅包。然後想起自己對算法感興趣,以前也看過一些公衆號有講過搶紅包算法,今天就更新一遍關於搶紅包的算法,對學過數據結構或者對搶紅包感興趣的可以看一看。本文就講兩個搶紅包算法。
PS:關於搶紅包算法我是參看公衆號“程序員小灰”。這個公衆號是引領我學數據結構的公衆號,通過漫畫的形式講得很通俗易懂。
搶紅包算法的要求
假設有10元錢,10個人分:
- 每個人至少分到0.01元,不可以分到0元
- 每個人分到的金額加起來要等於10元,不可以多於10元,也不可以少於10元
- 每個人分的金額要儘可能隨機,不能差距太大
搶紅包一
當初大二學習數據結構的時候老師就有佈置一道作業題說叫我們回去寫一個類似於微信的搶紅包算法,然後下個星期看哪位同學寫得好。所以第一個搶紅包算法應該大家很容易理解。
思路
每個人每次搶到的金額範圍是:(0,剩餘金額)。
不過這個算法思路會違背“每個人分的金額隨機,不能差距太大”。
爲什麼會這樣,舉個例子:
假設有10元錢,10個人分。
第一個人的隨機範圍是(0,10),平均分到5元。
假設第一個人隨機分到5元,剩餘金額爲10-5=5元。
第二個人的隨機範圍是(0,5),平均分到2.5元。
假設第二個人隨機分到2.5元,剩餘金額爲5-2.5=2.5元。
第三個人的隨機範圍是(0,2.5),平均分到1.25元
以此類推,每一次隨機範圍越來越小,違背了“每個人分的金額隨機,不能差距太大”。
代碼
package zhihu;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author god-jiang
* @date 2020/1/26 16:49
*/
public class Algorithm {
public static List<Integer> divideRedPackage(Integer totalAmount, Integer totalPeopleNum) {
List<Integer> amountList = new ArrayList<>();
Integer restAmount = totalAmount;
Integer restPeopleNum = totalPeopleNum;
Random random = new Random();
for (int i = 0; i < totalPeopleNum - 1; i++) {
int amount = random.nextInt(restAmount - restPeopleNum - 1) + 1;
restAmount -= amount;
restPeopleNum--;
amountList.add(amount);
}
amountList.add(restAmount);
return amountList;
}
public static void main(String[] args) {
List<Integer> amountList = divideRedPackage(1000, 10);
for (Integer amount : amountList
) {
System.out.println("搶到金額" + new BigDecimal(amount).divide(new BigDecimal(100)));
}
}
}
結果
搶紅包二
思路
*每次搶到的金額=隨機範圍(0,M/N 2)
M表示剩餘紅包金額,N表示剩餘人數。這個公式保證了每次隨機金額的平均值是相等的。
舉個例子:
假設有10元錢,10個人分:
10/10 *2=2,所以第一個人分到的範圍是(0,2),平均可以分到1元。
假設第一個人隨機分到1元,那麼剩餘金額是10-1=9元。
9/9 *2=2,所以第二個人分到的範圍是(0,2),平均可以分到1元。
假設第二個人隨機分到1元,那麼剩餘金額是9-1=8元。
8/8 *2=2,所以第三個人的隨機範圍也是(0,2),平均可以分到1元。
以此類推,每一次隨機範圍都是相等的。
代碼
package zhihu;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author god-jiang
* @date 2020/1/26 15:39
*/
public class Algorithm {
public static List<Integer> divideRedPackage(Integer totalAmount, Integer totalPeopleNum) {
List<Integer> amountList = new ArrayList<>();
Integer restAmount = totalAmount;
Integer restPeopleNum = totalPeopleNum;
Random random = new Random();
for (int i = 0; i < totalPeopleNum - 1; i++) {
//保證金額範圍是[1,剩餘金額2倍),左閉右開
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(1000, 10);
for (Integer amount : amountList
) {
System.out.println("搶到金額" + new BigDecimal(amount).divide(new BigDecimal(100)));
}
}
}
結果
總結
搶紅包算法就只寫了兩個,第一個就是以前大二學習數據結構的時候老師佈置作業,我的想法就是大概這樣,分的不均。第二個算法就是看公衆號“程序員小灰”學習到的,很厲害,挺佩服這些大佬的,哈哈。
PS:本文提供的代碼紅包金額都是以分爲單位,因爲搶紅包最低都是0.01元。