文档章节

JAVA实现仿微信红包分配规则

小致dad
 小致dad
发布于 06/18 21:23
字数 1652
阅读 16
收藏 0

最近过年发红包拜年成为一种新的潮流,作为程序猿对算法的好奇远远要大于对红包的好奇,这里介绍一种自己想到的一种随机红包分配策略,还请大家多多指教。

算法介绍

一、红包金额限制

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

//最小红包额度
private static final int MINMONEY = 1;
//最大红包额度
private static final int MAXMONEY = 200 * 100;


二、判断红包金额是否合法

      注意这一步伴随着整个算法,我们不仅要在分配红包之前要判断金额是否合法,同样要在每个人暂定随机金额后也要判断剩余的金额是否合法。

private boolean isRight(int money, int count) {
	double avg = money / count;
	if (avg < MINMONEY) {
		return false;
	}
	if (avg > MAXMONEY) {
		return false;
	}
	return true;
}


三、随机产生一个红包

      这里我们采用随机的方式产生一个在MINMONEY和MAXMONEY之间的一个红包,产生红包之后,我们需要判断剩余的钱是否是合法红包,如果不是合法红包,我们就重新产生分配方案,在重新产生分配方案的时候,我们需要确定一个事情,是产生的红包过大还是过小,如果红包过大,下次就随机一个小值到本次红包金额的一个红包,如果红包金额过小,我们就产生一个红包金额到大值的一个红包。

private int random(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(money1, count -1)) {
		return one;
	} else {
		double avg = money1 / (count - 1);
		if (avg < MINMONEY) {
			//递归调用,修改红包最大金额
			return random(money, minS, one, count);
		}else if (avg > MAXMONEY) {
			//递归调用,修改红包最小金额
			return random(money, one, maxS, count);
		}
	}
	return one;
}

第三步优化

      首先感谢子冬童鞋给我提供的优化方案:在随机产生红包的时候,我们知道随机一个红包后,剩余的红包个数,这时我们又知道红包的最大值、最小值,那么我们就知道了剩余金额需要在一个范围内,因此也就知道了这个产生的随机红包的最值,所以每次产生下一个红包只需要一次随机即可。举个简单的例子,加入现在有一个5分4个的红包,每个红包要求至少1分,最大20000分,那么在分出第一个红包后,剩余3个红包的钱数要在1 * 3 = 3(分) 和 20000 * 3 = 60000(分)之间,因此也就是说,分配第一个红包的随机金额要在5 - 60000 = -59995(分)和 5 - 3 = 2(分)之间,又由于我们对红包的金额要求在1~20000之间,因此确定第一次随机金额的范围是[1分,2分]。这种随机产生红包的方案要远远优于第三步中提供的方案,在此再次感谢子冬同学提供的优化方案。我们只需要将下述方法替换源代码中的方法即可实现红包随机优化。

	private int random(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 maxY = money - (count - 1) * minS;
		//分配红包正确情况,允许红包的最小值
		int minY = money - (count - 1) * maxS;
		//随机产生红包的最小值
		int min = minY > minS ? minY : minS;
		//随机产生红包最大值
		max = maxY < max ? maxY : max;
		//随机产生一个红包
		return (int)Math.rint(Math.random() * (max - min) + min);
	}

四、实现红包分配

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

//每个红包最大是平均值的倍数
private static final double TIMES = 2.1;   

public List<Integer> splitRedPackets(int money, int count) {
	if (!isRight(money, count)) {
		return null;
	}
	List<Integer> list = new ArrayList<Integer>();
	//红包最大金额为平均金额的TIMES倍
	int max = (int) (money * TIMES / count);
	max = max > MAXMONEY ? MAXMONEY : max;
	for (int i = 0; i < count; i++) {
		int one = random(money, MINMONEY, max, count - i);
		list.add(one);
		money -= one;
	}
	return list;
}

红包分配方案评估

      上面介绍了红包的基本算法,下面我们就对算法进行一次验证,假设有一个200元100份的红包,我们来看一下最后的分配方案。

img

完整代码

 /**  
 *@Description:     
 */ 
package com.lulei.weixin.util;  

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

import com.lulei.util.JsonUtil;
  
public class RedPacketUtil {
	//最小红包额度
	private static final int MINMONEY = 1;
	//最大红包额度
	private static final int MAXMONEY = 200 * 100;
	//每个红包最大是平均值的倍数
	private static final double TIMES = 2.1;
	
	/**
	 * @param money
	 * @param count
	 * @return
	 * @Author:lulei  
	 * @Description: 拆分红包
	 */
	public List<Integer> splitRedPackets(int money, int count) {
		if (!isRight(money, count)) {
			return null;
		}
		List<Integer> list = new ArrayList<Integer>();
		//红包最大金额为平均金额的TIMES倍
		int max = (int) (money * TIMES / count);
		max = max > MAXMONEY ? MAXMONEY : max;
		for (int i = 0; i < count; i++) {
			int one = random(money, MINMONEY, max, count - i);
			list.add(one);
			money -= one;
		}
		return list;
	}
	
	/**
	 * @param money
	 * @param minS
	 * @param maxS
	 * @param count
	 * @return
	 * @Author:lulei  
	 * @Description: 随机红包额度
	 */
	private int random(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(money1, count -1)) {
			return one;
		} else {
			double avg = money1 / (count - 1);
			if (avg < MINMONEY) {
				//递归调用,修改红包最大金额
				return random(money, minS, one, count);
			}else if (avg > MAXMONEY) {
				//递归调用,修改红包最小金额
				return random(money, one, maxS, count);
			}
		}
		return one;
	}
	
	/**
	 * @param money
	 * @param count
	 * @return
	 * @Author:lulei  
	 * @Description: 此种红包是否合法
	 */
	private boolean isRight(int money, int count) {
		double avg = money / count;
		if (avg < MINMONEY) {
			return false;
		}
		if (avg > MAXMONEY) {
			return false;
		}
		return true;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub  
		RedPacketUtil util = new RedPacketUtil();
		System.out.println(JsonUtil.parseJson(util.splitRedPackets(20000, 100)));
	}
}

 

本文转载自:https://blog.csdn.net/xiaojimanman/article/details/50708860

共有 人打赏支持
小致dad
粉丝 139
博文 536
码字总数 580320
作品 0
济南
技术主管
私信 提问
关于电商中复杂促销手段的一个解决思路-规则表达式

一般来说,只要是面向零售,不管是B2C,C2C还是B2B2C模式,商城的促销模式都是差不多的,比如满就送,满x减x,满x赠x,满x折扣x,组合销售,优惠券等等。所有促销活动都有明确的起止周期,超...

jim19770812
2014/08/13
0
10
一个疑似JVM GC BUG的案例分析

概述 一般来我们公司面试,我都会习惯性地问点JVM相关的问题,当然如果他觉得JVM掌握得不错,我会适当多问点,毕竟知音难觅,难得在这么一条”狭路上相逢”。(如果你想在技术深度上有所积累,...

PerfMa
09/03
0
0
Java虚拟机内存管理(一)—内存划分

Java 与 C++ 之间有一堵由内存动态分配和垃圾收集技术所围成的 “高墙”,墙外面的人想进去,墙里面的人却想出来。——《深入理解Java虚拟机:JVM高级特性与最佳时实践(第二版)》周志明 Ja...

Wizey
08/30
0
0
Java微信开发_00_资源汇总贴

1.微信公众平台技术文档(https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432) 2.微信企业号开发接口文档(http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%BB%E......

rayner
2017/08/07
0
0
Java虚拟机JVM内部体系结构

Java虚拟机JVM内部体系结构 易百教程移动端:请扫描本页面底部(右侧)二维码并关注微信公众号,回复:"教程" 选择相关教程阅读或直接访问:http://m.yiibai.com 。 JVM(Java虚拟机)是一个抽象...

LYQ1990
07/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS 安装PHP5和PHP7

安装PHP5 下载解压二进制包 [root@test-a src]# cd /usr/local/src/[root@test-a src]# wget http://cn2.php.net/distributions/php-5.6.32.tar.bz2[root@test-a src]# tar jxvf php-5.6......

野雪球
今天
4
0
windows上类似dnsmasq的软件Dual DHCP DNS Server

官网地址:http://dhcp-dns-server.sourceforge.net/官网定向的下载地址:https://sourceforge.net/projects/dhcp-dns-server/files/ 设置参考地址:http://blog.51cto.com/zhukeqiang/18264......

xueyuse0012
今天
3
0
LinkedHashMap源码解析

前言 HashMap中的元素时无序的,也就是说遍历HashMap的时候,顺序和放入的顺序是不一样的。 如果需要有序的Map,就可以采用LinkedHashMap. LinkedHashMap通过维护一个包含所有元素的双向链表,...

grace_233
今天
4
0
初识flask

文档 0.10.1版本 http://www.pythondoc.com/flask/index.html 1.0.2版本 https://dormousehole.readthedocs.io/en/latest/ 安装flask $ pip3 install flaskCollecting flask Downloading......

yimingkeji
昨天
6
0
Akka系统《sixteen》译

Actor是一个封装状态(state)和行为(behavior)的对象,它们只通过交换消息通信(放入收件人邮箱的邮件)。从某种意义上说,Actor是最严格的面向对象编程形式,但它更适合将他们视为人:在与Act...

woshixin
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部