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

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

算法介绍

一、红包金额限制

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

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

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

?
1
2
3
4
5
6
7
8
9
10
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之间的一个红包,产生红包之后,我们需要判断剩余的钱是否是合法红包,如果不是合法红包,我们就重新产生分配方案,在重新产生分配方案的时候,我们需要确定一个事情,是产生的红包过大还是过小,如果红包过大,下次就随机一个小值到本次红包金额的一个红包,如果红包金额过小,我们就产生一个红包金额到大值的一个红包。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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;
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//每个红包最大是平均值的倍数
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份的红包,我们来看一下最后的分配方案。

完整代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
  *@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 )));
  }
}

以上就是本文的全部内容,希望对大家学习java程序设计有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值