1. 程式人生 > >實時隨機數演算法(微信紅包分配演算法)

實時隨機數演算法(微信紅包分配演算法)

微信紅包演算法在知乎上面有個專題討論,其實紅包的發放的隨機演算法,有兩種做法:

1、預生產:

無外乎是在發紅包的時候,隨機去把金額生成到某個容器當中,然後要用的時候,一個一個的POP;

2、實時隨機

使用者在搶紅包的時候,根據隨機演算法,算出這次使用者要搶到多少

本文講的是第二種。

之所以沒弄第一種,是因為我們的研發同學張智哥,在以前的紅包發放演算法裡面就是用的第二種,而我在徵求他的意見看是否改成預生產的時候,他想偷個懶,不想再加表、動流程啥的。我想想也是,動流程動出問題來了,到時候還是得哥背鍋。雖然作為研發一直都有豐富的背鍋經驗和強大的背鍋內心,但是,能夠少背個還是少背個。

從此,也就開始了我比較黑暗的調整演算法、調整引數的過程。

紅包演算法關鍵是要簡單、迅速的找出隨機值,而這個坑,什麼正態分佈修正、什麼平方後再開方取隨機數優化,我都嘗試過。

結果很慘淡:要麼是前面的拿大頭的機率很大,要麼是後面的拿大頭的機率很大,而前面拿大頭,或者後面拿大頭,是我們運營的大爺們吐槽我們的隨機演算法做得不如微信好的一個重要原因(尼瑪談需求的時候不講,還弄了個隨機數範圍要在8%到74%之間做限制,覺得不爽就讓研發背鍋)。

廢話完了,說下我的演算法:

其實很簡單,兩個隨機數,一個隨機0到2;一個隨機-1到1;兩個隨機數之和乘以均值,就是這次跑出來的隨機數。然後再做下上下限的保護就行了。

我的程式碼裡面偷了個懶,只做了下限,沒做上限的保護。因為畢竟是研究演算法,不是實際生產環境程式碼。

	public static void dispath(int total, int people, int min){
		
		for(int i = 0; i < people - 1 ; i++ ){
			int leftPeople = people - i;

			double avg = Double.valueOf(total)/leftPeople;
			double ratio1 = getRandom(0, 2);
			double ratio2 = getRandom(-1, 1);
			double ratio = ratio1+ratio2;
			int cur = (int) Math.floor(ratio * avg) > min ? (int) Math.floor(ratio * avg)  : min;
			
			// 扣減總額閱點數目
			total = total - cur;
			
			System.out.format("第 %d 個紅包: %d 閱點,剩下: %d 閱點\n", i + 1, cur,	total);
		}
		
		// 剩餘的就是最後一個使用者的閱點額度
		System.out.format("第 %d 個紅包: %d 閱點,剩下: 0 閱點\n", people, total);	
	}

結果嘛,還馬馬虎虎,反正跑了幾次測試,基本上還可以滿足要求,反正最大和最小的,不會固定在某個地方出現了。