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