微信紅包的隨機演算法是怎樣實現的?

caiyongji發表於2018-01-30

我在知乎上看到這樣一個問題微信紅包的隨機演算法是怎樣實現的?

有人說騰訊大致是這樣實現的:

public static double getRandomMoney(LeftMoneyPackage _leftMoneyPackage) {
    // remainSize 剩餘的紅包數量
    // remainMoney 剩餘的錢
    if (_leftMoneyPackage.remainSize == 1) {
        _leftMoneyPackage.remainSize--;
        return (double) Math.round(_leftMoneyPackage.remainMoney * 100) / 100;
    }
    Random r     = new Random();
    double min   = 0.01; //
    double max   = _leftMoneyPackage.remainMoney / _leftMoneyPackage.remainSize * 2;
    double money = r.nextDouble() * max;
    money = money <= min ? 0.01: money;
    money = Math.floor(money * 100) / 100;
    _leftMoneyPackage.remainSize--;
    _leftMoneyPackage.remainMoney -= money;
    return money;
}
複製程式碼

也有人做了正太分佈、方差分析、迴歸分析、統計模擬等,圖太長我就不貼了。

然而

  1. 所有答案都是“取時隨機”,即設計“紅包池”的概念,然後在抽取時隨機取數。
  2. 所有答案都是“錢的隨機”,即隨機金額,然後return。

下面我們換個思路,現在我們把所有的錢換成1分的硬幣,把紅包想象成罐子,然後撒幣

/**
 * @param count 紅包數
 * @param money 總金額
 * @return
 */
public static Integer[] ranRedPac(Integer count, Integer money) {
	Integer[] result = new Integer[count];
	for (int i = 1; i <= money; i++) {
		int n = new Random().nextInt(count);
		result[n] = result[n] == null ? 1 : result[n] + 1;
	}
	return result;
}

//測試
public static void main(String[] args) {
	Arrays.asList(ranRedPac(10, 5000000)).forEach(i -> System.out.println(i));
	System.out.println("sum: " + Arrays.asList(ranRedPac(10, 50)).stream().mapToInt(i -> i).sum());
}
複製程式碼

每分錢隨機選擇紅包。

至於什麼迴歸分析,統計模擬統統用不上

本例中我們摒棄“抽取”、“隨機金額”這樣的傳統概念,使錢擁有選擇意識,執行“隨機”行為,自然而然紅包就有了隨機金額的屬性。

改變一下思路,別把簡單問題複雜化。

我們在編碼設計時,通常會考慮現實生活中的邏輯,並把物件抽象成類,行為抽象成方法。但是,我們偶爾也要考慮思維反轉

當然,我的程式碼有一定的弊端。

思維是最重要的。

相關文章