Java實(shí)現(xiàn)微信紅包分配規(guī)則
最近過年發(fā)紅包拜年成為一種新的潮流,作為程序猿對(duì)算法的好奇遠(yuǎn)遠(yuǎn)要大于對(duì)紅包的好奇,這里介紹一種自己想到的一種隨機(jī)紅包分配策略,還請(qǐng)大家多多指教。
算法介紹
一、紅包金額限制
對(duì)于微信紅包,我們知道沒人隨機(jī)的最小紅包是1分,最大金額是200元,這里我們同樣來設(shè)置紅包的范圍,下面代碼我們統(tǒng)一金錢的單位為分。
//最小紅包額度 private static final int MINMONEY = 1; //最大紅包額度 private static final int MAXMONEY = 200 * 100;
二、判斷紅包金額是否合法
注意這一步伴隨著整個(gè)算法,我們不僅要在分配紅包之前要判斷金額是否合法,同樣要在每個(gè)人暫定隨機(jī)金額后也要判斷剩余的金額是否合法。
private boolean isRight(int money, int count) {
double avg = money / count;
if (avg < MINMONEY) {
return false;
}
if (avg > MAXMONEY) {
return false;
}
return true;
}
三、隨機(jī)產(chǎn)生一個(gè)紅包
這里我們采用隨機(jī)的方式產(chǎn)生一個(gè)在MINMONEY和MAXMONEY之間的一個(gè)紅包,產(chǎn)生紅包之后,我們需要判斷剩余的錢是否是合法紅包,如果不是合法紅包,我們就重新產(chǎn)生分配方案,在重新產(chǎn)生分配方案的時(shí)候,我們需要確定一個(gè)事情,是產(chǎn)生的紅包過大還是過小,如果紅包過大,下次就隨機(jī)一個(gè)小值到本次紅包金額的一個(gè)紅包,如果紅包金額過小,我們就產(chǎn)生一個(gè)紅包金額到大值的一個(gè)紅包。
private int random(int money, int minS, int maxS, int count) {
//紅包數(shù)量為1,直接返回金額
if (count == 1) {
return money;
}
//如果最大金額和最小金額相等,直接返回金額
if (minS == maxS) {
return minS;
}
int max = maxS > money ? money : maxS;
//隨機(jī)產(chǎn)生一個(gè)紅包
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) {
//遞歸調(diào)用,修改紅包最大金額
return random(money, minS, one, count);
}else if (avg > MAXMONEY) {
//遞歸調(diào)用,修改紅包最小金額
return random(money, one, maxS, count);
}
}
return one;
}
四、實(shí)現(xiàn)紅包分配
這里為了避免某一個(gè)紅包占用大量資金,我們需要設(shè)定非最后一個(gè)紅包的最大金額,我們把他設(shè)置為紅包金額平均值的N倍;有了一、二、三中的方法,我們就可以來實(shí)現(xiàn)紅包的分配了。
//每個(gè)紅包最大是平均值的倍數(shù)
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;
}
紅包分配方案評(píng)估
上面介紹了紅包的基本算法,下面我們就對(duì)算法進(jìn)行一次驗(yàn)證,假設(shè)有一個(gè)200元100份的紅包,我們來看一下最后的分配方案。

完整代碼
/**
*@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;
//每個(gè)紅包最大是平均值的倍數(shù)
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: 隨機(jī)紅包額度
*/
private int random(int money, int minS, int maxS, int count) {
//紅包數(shù)量為1,直接返回金額
if (count == 1) {
return money;
}
//如果最大金額和最小金額相等,直接返回金額
if (minS == maxS) {
return minS;
}
int max = maxS > money ? money : maxS;
//隨機(jī)產(chǎn)生一個(gè)紅包
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) {
//遞歸調(diào)用,修改紅包最大金額
return random(money, minS, one, count);
}else if (avg > MAXMONEY) {
//遞歸調(diào)用,修改紅包最小金額
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)));
}
}
更多精彩內(nèi)容請(qǐng)點(diǎn)擊《Android微信開發(fā)教程匯總》,《java微信開發(fā)教程匯總》歡迎大家學(xué)習(xí)閱讀。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家學(xué)習(xí)java程序設(shè)計(jì)有所幫助。
相關(guān)文章
springboot?aop配合反射統(tǒng)一簽名驗(yàn)證實(shí)踐
這篇文章主要介紹了springboot?aop配合反射統(tǒng)一簽名驗(yàn)證實(shí)踐,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Springboot使用Spring Data JPA實(shí)現(xiàn)數(shù)據(jù)庫操作
Spring Data JPA 是 Spring 基于 Spring Data 框架、在JPA 規(guī)范的基礎(chǔ)上開發(fā)的一個(gè)框架,使用 Spring Data JPA 可以極大地簡(jiǎn)化JPA 的寫法,本章我們將詳細(xì)介紹在Springboot中使用 Spring Data JPA 來實(shí)現(xiàn)對(duì)數(shù)據(jù)庫的操作2021-06-06
SpringBoot多種環(huán)境自由切換的實(shí)現(xiàn)
本文主要介紹了SpringBoot多種環(huán)境自由切換的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
Mac使用Idea配置傳統(tǒng)SSM項(xiàng)目(非maven項(xiàng)目)
本文主要介紹了Mac使用Idea配置傳統(tǒng)SSM項(xiàng)目(非maven項(xiàng)目),將展示如何設(shè)置項(xiàng)目結(jié)構(gòu)、添加依賴關(guān)系等,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01
ruoyi-springboot框架新增模塊調(diào)接口報(bào)404的解決方案
這篇文章主要介紹了ruoyi-springboot框架新增模塊調(diào)接口報(bào)404的解決方案,文中通過代碼示例給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-03-03
SpringBoot 集成MQTT實(shí)現(xiàn)消息訂閱的詳細(xì)代碼
本文介紹了如何在SpringBoot中集成MQTT并實(shí)現(xiàn)消息訂閱,主要步驟包括添加依賴、配置文件設(shè)置、啟動(dòng)類注解、MQTT配置類、消息處理器配置、主題緩存、動(dòng)態(tài)數(shù)據(jù)庫主題配置以及消息處理服務(wù),感興趣的朋友跟隨小編一起看看吧2024-11-11

