文档章节

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

小致dad
 小致dad
发布于 06/18 21:23
字数 1652
阅读 8
收藏 0
点赞 0
评论 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
粉丝 116
博文 514
码字总数 560933
作品 0
济南
技术主管
关于电商中复杂促销手段的一个解决思路-规则表达式

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

jim19770812
2014/08/13
0
10
Java虚拟机JVM内部体系结构

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

LYQ1990
07/18
0
0
阿里历年经典Java面试题汇总

Volatile的特征: A、禁止指令重排(有例外) B、可见性 Volatile的内存语义: 当写一个volatile变量时,JMM会把线程对应的本地内存中的共享变量值刷新到主内存。 当读一个volatile变量时,J...

Java团长17
07/11
0
0
对象和数组并不是都在堆上分配内存的。

前段时间,给星球的球友们专门码了一篇文章《深入分析Java的编译原理》,其中深入的介绍了Java中的javac编译和JIT编译的区别及原理。并在文中提到:JIT编译除了具有缓存的功能外,还会对代码...

05/13
0
0
Java 使用 happen-before 规则实现共享变量的同步操作

前言 熟悉 Java 并发编程的都知道,JMM(Java 内存模型) 中的 happen-before(简称 hb)规则,该规则定义了 Java 多线程操作的有序性和可见性,防止了编译器重排序对程序结果的影响。按照官方的...

stateIs0
01/20
0
0
JVM性能优化, Part 1 ―― JVM简介

众所周知,Java应用程序是运行在JVM上的,但是你对JVM有所了解么?作为这个系列文章的第一篇,本文将对经典Java虚拟机的运行机制做简单介绍,内容包括“一次编写,到处运行”的利弊、垃圾回收...

梁杰_Jack
2014/10/30
0
0
Oracle HotSpot虚拟机的JVM栈和方法区实现

Java Heap和Method Area是JVM中内存占用最大的区域,也是监控和调优的重点。 下图使用jvisualvm工具截取,Perm是永久代(Permanent Generation)、Old是年老代(Old Generation)、Eden Spac...

foodon
2014/12/10
0
0
Java 面试知识点解析(三)——JVM篇

前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大部...

我没有三颗心脏
05/16
0
0
sharding-jdbc源码分析—准备工作

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7831817c1da8 接下来对sharding-jdbc源码的分析基于tag为源码,根据sharding-jdbc Features深入学习sharding-jdbc的几个主要特性...

飞哥-Javaer
05/03
0
0
AEAI WX 微信扩展框架 V1.0 版本发版说明

AEAI WX 微信扩展框架是基于 Java 封装的微信公众号二次开发框架,基于该框架可以快速接入微信,实现自定义菜单创建、信息按规则自动回复、集成企业的线上系 统(HR、CRM、微店、网站等)、同...

数通畅联
2015/05/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

云拿 无人便利店

附近(上海市-航南路)开了家无人便利店.特意进去体验了一下.下面把自己看到的跟大家分享下. 经得现场工作人员同意后拍了几张照片.从外面看是这样.店门口的指导里强调:不要一次扫码多个人进入....

周翔
10分钟前
0
0
Java设计模式学习之工厂模式

在Java(或者叫做面向对象语言)的世界中,工厂模式被广泛应用于项目中,也许你并没有听说过,不过也许你已经在使用了。 简单来说,工厂模式的出现源于增加程序序的可扩展性,降低耦合度。之...

路小磊
24分钟前
0
0
npm profile 新功能介绍

转载地址 npm profile 新功能介绍 npm新版本新推来一个功能,npm profile,这个可以更改自己简介信息的命令,以后可以不用去登录网站来修改自己的简介了 具体的这个功能的支持大概是在6这个版...

durban
35分钟前
0
0
Serial2Ethernet Bi-redirection

Serial Tool Serial Tool is a utility for developing serial communications, custom protocols or device testing. You can set up bytes to send accordingly to your protocol and save......

zungyiu
41分钟前
0
0
python里求解物理学上的双弹簧质能系统

物理的模型如下: 在这个系统里有两个物体,它们的质量分别是m1和m2,被两个弹簧连接在一起,伸缩系统为k1和k2,左端固定。假定没有外力时,两个弹簧的长度为L1和L2。 由于两物体有重力,那么...

wangxuwei
56分钟前
0
0
apolloxlua 介绍

##项目介绍 apolloxlua 目前支持javascript到lua的翻译。可以在openresty和luajit里使用。这个工具分为两种模式, 一种是web模式,可以通过网页使用。另外一种是tool模式, 通常作为大规模翻...

钟元OSS
今天
0
0
Mybatis入门

简介: 定义:Mybatis是一个支持普通SQL查询、存储过程和高级映射的持久层框架。 途径:MyBatis通过XML文件或者注解的形式配置映射,实现数据库查询。 特性:动态SQL语句。 文件结构:Mybat...

霍淇滨
今天
0
0
开发技术瓶颈期,如何突破

前言 读书、学习的那些事情,以前我也陆续叨叨了不少,但总觉得 “学习方法” 就是一个永远在路上的话题。个人的能力、经验积累与习惯方法不尽相同,而且一篇文章甚至一本书都很难将学习方法...

_小迷糊
今天
0
0
安装tensorflow-XXX报错

报错: tensorflow-0.5.0-cp27-none-linux_x86_64.whl is not a supported wheel on this platform. 解决: wget https://bootstrap.pypa.io/get-pip.py sudo python2.7 get-pip.py sudo p......

Yao--靠自己
今天
0
0
JVM学习手册(一):JVM模型

一直从事JAVA开发,天天和JVM打交道,仔细想想对JVM还真的不是特别了解,实在是不应该.周六看了许多资料,也算有点心得,记录一下。 JVM内存模型分为5个区域:方法区,堆,虚拟机栈,本地方法栈,程序计...

勤奋的蚂蚁
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部