1. 程式人生 > >Java篇:WeChat 模仿微信紅包的核心遞迴演算法

Java篇:WeChat 模仿微信紅包的核心遞迴演算法

模仿WeChat的拼手氣紅包 ,例如:10000元傳送50個包。

這50個紅包隨機分配,但是最後相加等於10000.

採用隨機數,隨機紅包金額。

又制定規則,不斷地遞迴運算。

限制最小的紅包金額,例如:0.01,因為考慮人性化,最小的紅包不能是0.

不限制可發出的紅包總額。

但是要限制可得到的最大紅包額度,比如:拼手氣可得到的最大的紅包為紅包總額的60%,剩下的40%由其他人分配。

因為Java的基礎資料型別限制,採用擴大100倍的方式,最後得到的金額除以100.

package com.hc.money;

import java.util.ArrayList;
import java.util.List;

public class Money {

	// 最小紅包額度
	private static final int MINMONEY = 1;// 0.01
	// 每個紅包最大是平均值的倍數
	private static final double TIMES = 2.1;

	public static void main(String[] args) {
		double send = 111.11;// 紅包總額
		int sendcount = 43;// 數量
		List<Integer> Integers = sendMoney((int) (send * 100), sendcount);// 紅包擴100倍
		long l = 0;
		for (Integer integer : Integers) {
			l += integer;
			 System.out.println(integer * 1.0 / 100);
		}
		System.out.println(l * 1.0 / 100);// 丟失精度
	}

	/**
	 * 拆分紅包
	 * 
	 * @param money
	 * @param count
	 * @return
	 */
	public static List<Integer> sendMoney(int money, int count) {
		// 最大紅包額度 微信隨機紅包最大為200 為所發紅包一半
		int MAXMONEY = money / 2;
		List<Integer> list = new ArrayList<>();
		if (!isRight(MAXMONEY, money, count)) {// 驗證
			list.add(money);
			return list;// 不符合規則,則返回總數
		}

		// 紅包最大金額為平均金額的TIMES倍
		int max = (int) (money * TIMES / count);
		max = max > MAXMONEY ? MAXMONEY : max;
		for (int i = 0; i < count; i++) {
			int one = random(MAXMONEY, money, MINMONEY, max, count - i);
			list.add(one); // 除以100,轉換成需要的數目
			money -= one;// 紅包總額減去生成的紅包
		}
		return list;
	}

	/**
	 * 隨機紅包額度
	 * 
	 * @param money
	 * @param minS
	 * @param maxS
	 * @param count
	 * @return
	 */
	private static int random(int MAXMONEY, int money, int minS, int maxS, int count) {
		// 紅包數量為1,直接返回金額
		if (count == 1) {
			return money;
		}
		// 如果最大金額和最小金額相等,直接返回金額
		if (minS == maxS) {
			return minS;
		}
		int max = maxS > money ? money : maxS;
		// 隨機產生一個紅包
		int one = ((int) Math.rint(Math.random() * (max - minS) + minS)) % max + 1;

		int money1 = money - one;
		// 判斷該種分配方案是否正確
		if (isRight(MAXMONEY, money1, count - 1)) {
			return one;
		} else {
			double avg = money1 / (count - 1);
			if (avg < MINMONEY) {
				// 遞迴呼叫,修改紅包最大金額
				return random(MAXMONEY, money, minS, one, count);
			} else if (avg > MAXMONEY) {
				// 遞迴呼叫,修改紅包最小金額
				return random(MAXMONEY, money, one, maxS, count);
			}
		}
		return one;
	}

	/**
	 * 此種紅包是否合法
	 * 
	 * @param money
	 * @param count
	 * @return
	 */
	private static boolean isRight(int MAXMONEY, int money, int count) {
		double avg = money / count;
		if (avg < MINMONEY) {
			return false;
		}
		if (avg > MAXMONEY) {
			return false;
		}
		return true;
	}

	// String one =Math.random() * 100+"";
	// String two=one.substring(0,one.lastIndexOf(".")+3);
	// Math.random()= 0.5346774447849648
	// Math.rint 四捨五入

	// if (integer.length() > 2) {
	// integer = integer.substring(0, integer.length() - 2) + "." +
	// integer.substring(integer.length() - 2);
	// } else if (integer.length() == 2) {
	// integer = "0." + integer;
	// } else if (integer.length() == 1) {
	// integer = "0.0" + integer;
	// }
}

如果隨機出不符合規則的紅包,則放棄,繼續遞迴運算。

最後的一個紅包就是剩下的金額。

隨機出適合的紅包後,放進紅包list集合中,修改獎池中剩餘的金額,需要格外注意資料的精度,最後展示出來。