Java仿实现微信红包分配算法

点此直达原文


算法介绍

一、红包金额限制

  对于微信红包,我们知道每人随机的最小红包是1分,最大金额是200元,这里我们同样来设置红包的范围,下面代码我们统一金钱单位为分。

/**
	 * 1.总金额不超过200*100  单位是分
	 * 2.每个红包都要有钱,最低不能低于1分,最大金额不能超过200*100
	 */
	private static final int MINMONEY = 1;
	private static final int MAXMONEY = 200*100;
二、判断红包金额是否合法

在分配红包前判断其是否合法

/**
	 * 红包合法性校验
	 * @param money
	 * @param count
	 * @return
	 */
	private boolean isRight(int money,int count){
		double avg = money/count;
		//小于最小金额
		if (avg<MINMONEY) {
			return false;
		}else if (avg>MAXMONEY) {
			return false;
		}
		return true;
	}


三、随机产生一个红包

        在随机产生红包的时候,我们知道随机一个红包后,剩余的红包个数,这时我们又知道红包的最大值、最小值、那么我们就知道了剩余金额需要在一个范围内,因此也知道了这个产生的随机红包的最值,所以每次产生下个红包只需一次随机即可。

        举个简单的例子,加入现在有一个5分4个红包,每个红包要求至少1分,最大20000分,那么分出第一个红包后,剩余3个红包的钱数要在1*3=3(分),20000*3=60000(分)之间,因此也就是说,分配第一个红包的随机金额在5-60000=59995(分)和5-3=2(分)之间,又由于我们对红包的金额要求在1~20000之间,因此确定第一次随机金额的范围是【1分,2分】之间。

	/**
	 * 随机分配一个红包
	 * @param mnoney
	 * @param minS:最小金额
	 * @param maxS:最大金额
	 * @param count
	 * @return
	 */
	private int randomRedPacket(int money,int minS,int maxS,int count){
		//若只有一个,直接返回红包
		if (count==1) {
			return money;
		}
		//如果最大金额和最小金额相等,直接返回金额
		if (minS==maxS) {
			return minS;
		}
		int max=maxS>money?money:maxS;
		//分配红包正确情况,允许红包的最大值
		int maxY = money-(count-1)*minS;
		//分配红包正确情况,允许红包最小值
		int minY = money-(count-1)*maxS;
		//随机产生红包的最小值
		int min = minS>minY?minS:minY;
		//随机产生红包的最大值
		max = max>maxY?maxY:max;
		//随机产生一个红包
		return (int)Math.rint(Math.random()*(max-min) +min);
	}


四、实现红包的分配

     这里为了避免某一个红包占用大量资金,我们需要设定非最后一个红包的最大金额,我们把他设置成红包金额平均值的N倍;有了以上方法,就能实现红包分配了

	/**
	 * 拆分红包
	 * @param money	红包金额
	 * @param count 个数
	 * @return
	 */
	public List<Integer> splitRedPacket(int money,int count){
		//红包合法性分析
		if (!isRight(money, count)) {
			return null;
		}
		//红包列表
		List<Integer> list = new ArrayList<>();
		//每个红包的最大的金额为平均金额的TIMES倍
		int max = (int)(money*TIMES/count);
		max = max>MAXMONEY?MAXMONEY:max;
		//分配红包
		for(int i=0;i<count;i++){
			int one = randomRedPacket(money, MINMONEY, max, count-i);
			list.add(one);
			money-=one;
		}
		return list;
	}





完整代码

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

/**
 * 
 * @author zy
 * @date 2017年10月13日 上午9:57:07
 * @Decription Java仿实现微信红包分配算法
 */
public class RedPacket {
	/**
	 * 1.总金额不超过200*100  单位是分
	 * 2.每个红包都要有钱,最低不能低于1分,最大金额不能超过200*100
	 */
	private static final int MINMONEY = 1;
	private static final int MAXMONEY = 200*100;
	
	/**
	 * 这里为了避免某一个红包占用大量资金,我们需要设定非最后一个红包的最大金额,
	 * 我们把他设置为红包金额平均值的N倍
	 */
	private static final double TIMES = 3.1;
	
	/**
	 * 红包合法性校验
	 * @param money
	 * @param count
	 * @return
	 */
	private boolean isRight(int money,int count){
		double avg = money/count;
		//小于最小金额
		if (avg<MINMONEY) {
			return false;
		}else if (avg>MAXMONEY) {
			return false;
		}
		return true;
	}
	
	/**
	 * 随机分配一个红包
	 * @param mnoney
	 * @param minS:最小金额
	 * @param maxS:最大金额
	 * @param count
	 * @return
	 */
	private int randomRedPacket(int money,int minS,int maxS,int count){
		//若只有一个,直接返回红包
		if (count==1) {
			return money;
		}
		//如果最大金额和最小金额相等,直接返回金额
		if (minS==maxS) {
			return minS;
		}
		int max=maxS>money?money:maxS;
		//分配红包正确情况,允许红包的最大值
		int maxY = money-(count-1)*minS;
		//分配红包正确情况,允许红包最小值
		int minY = money-(count-1)*maxS;
		//随机产生红包的最小值
		int min = minS>minY?minS:minY;
		//随机产生红包的最大值
		max = max>maxY?maxY:max;
		//随机产生一个红包
		return (int)Math.rint(Math.random()*(max-min) +min);
	}
	
	/**
	 * 拆分红包
	 * @param money	红包金额
	 * @param count 个数
	 * @return
	 */
	public List<Integer> splitRedPacket(int money,int count){
		//红包合法性分析
		if (!isRight(money, count)) {
			return null;
		}
		//红包列表
		List<Integer> list = new ArrayList<>();
		//每个红包的最大的金额为平均金额的TIMES倍
		int max = (int)(money*TIMES/count);
		max = max>MAXMONEY?MAXMONEY:max;
		//分配红包
		for(int i=0;i<count;i++){
			int one = randomRedPacket(money, MINMONEY, max, count-i);
			list.add(one);
			money-=one;
		}
		return list;
	}
	
	public static void main(String[] args) {
		RedPacket redPacket = new RedPacket();
		System.out.println(redPacket.splitRedPacket(20000, 100));
	}
}


  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值