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集合中,修改奖池中剩余的金额,需要格外注意数据的精度,最后展示出来。