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

算法介绍

一、红包金额限制

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

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * 1.总金额不能超过200*100 单位是分 
  3.      * 2.每个红包都要有钱,最低不能低于1分,最大金额不能超过200*100 
  4.      */  
  5.     private static final int MINMONEY =1;  
  6.     private static final int MAXMONEY =200*100;  
二、判断红包金额是否合法
      注意这一步伴随着整个算法,我们不仅要在分配红包之前要判断金额是否合法,同样要在每个人暂定随机金额后也要判断剩余的金额是否合法。
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /**  
  2.      * 红包 合法性校验  
  3.      * @param money  
  4.      * @param count  
  5.      * @return  
  6.      */  
  7.     private boolean isRight(int money, int count) {  
  8.         double avg =money/count;  
  9.         //小于最小金额  
  10.         if(avg<MINMONEY){  
  11.             return false;  
  12.         //大于最大金额      
  13.         }else if(avg>MAXMONEY){  
  14.             return false;  
  15.         }  
  16.         return true;  
  17.     }  
三、随机产生一个红包
      这里我们采用随机的方式产生一个在MINMONEY和MAXMONEY之间的一个红包,产生红包之后,我们需要判断剩余的钱是否是合法红包,如果不是合法红包,我们就重新产生分配方案,在重新产生分配方案的时候,我们需要确定一个事情,是产生的红包过大还是过小,如果红包过大,下次就随机一个小值到本次红包金额的一个红包,如果红包金额过小,我们就产生一个红包金额到大值的一个红包。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * 随机分配一个红包 
  3.      * @param money 
  4.      * @param minS :最小金额 
  5.      * @param maxS :最大金额(每个红包的默认Times倍最大值) 
  6.      * @param count 
  7.      * @return 
  8.      */  
  9.     private int randomRedPacket(int money, int minS, int maxS, int count) {  
  10.         //若是只有一个,直接返回红包  
  11.         if(count==1){  
  12.             return money;  
  13.         }  
  14.         //若是最小金额红包 == 最大金额红包, 直接返回最小金额红包  
  15.         if(minS ==maxS){  
  16.             return minS;  
  17.         }  
  18.         //校验 最大值 max 要是比money 金额高的话? 去 money 金额  
  19.         int max = maxS>money ? money : maxS;  
  20.         //随机一个红包 = 随机一个数* (金额-最小)+最小  
  21.         int one =((int)Math.rint(Math.random()*(max-minS)+minS));  
  22.         //剩下的金额  
  23.         int moneyOther =money-one;  
  24.         //校验这种随机方案是否可行,不合法的话,就要重新分配方案  
  25.         if(isRight(moneyOther, count-1)){  
  26.             return one;  
  27.         }else{  
  28.             //重新分配  
  29.             double avg =moneyOther /(count-1);  
  30.             //本次红包过大,导致下次的红包过小;如果红包过大,下次就随机一个小值到本次红包金额的一个红包  
  31.             if(avg<MINMONEY){  
  32.                  //递归调用,修改红包最大金额    
  33.                 return randomRedPacket(money, minS, one, count);  
  34.             }else if(avg>MAXMONEY){  
  35.                  //递归调用,修改红包最小金额    
  36.                 return randomRedPacket(money, one, maxS, count);  
  37.             }  
  38.         }  
  39.         return one;  
  40.     }  
四、实现红包分配
      这里为了避免某一个红包占用大量资金,我们需要设定非最后一个红包的最大金额,我们把他设置为红包金额平均值的N倍;有了一、二、三中的方法,我们就可以来实现红包的分配了。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 这里为了避免某一个红包占用大量资金,我们需要设定非最后一个红包的最大金额,我们把他设置为红包金额平均值的N倍; 
  3.  */  
  4. private static final double TIMES =2.1;   
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * 拆分红包 
  3.      * @param money :红包总金额 
  4.      * @param count :个数 
  5.      * @return 
  6.      */  
  7.     public List<Integer> splitRedPackets(int money,int count){  
  8.         //红包 合法性校验  
  9.         if(!isRight(money,count)){  
  10.             return null;  
  11.         }  
  12.         //红包列表  
  13.         List<Integer> list =new ArrayList<Integer>();  
  14.         //每个红包最大的金额为平均金额的Times 倍  
  15.         int max =(int)(money*TIMES/count);  
  16.           
  17.         max = max>MAXMONEY ? MAXMONEY : max;  
  18.         //分配红包  
  19.         for (int i = 0; i < count; i++) {  
  20.             int one = randomRedPacket(money,MINMONEY,max,count-i);  
  21.             list.add(one);  
  22.             money -=one;  
  23.         }  
  24.         return list;  
  25.     }  
五、完整代码:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.zeng.redEnvelopes;  
  2. import java.util.ArrayList;  
  3. import java.util.List;  
  4. /** 
  5.  * 微信随机分配红包算法 
  6.  *  
  7.  * @author leo-zeng 
  8.  * 
  9.  */  
  10. public class RedEnvelopesDemo {  
  11.     /** 
  12.      * 1.总金额不能超过200*100 单位是分 
  13.      * 2.每个红包都要有钱,最低不能低于1分,最大金额不能超过200*100 
  14.      */  
  15.     private static final int MINMONEY =1;  
  16.     private static final int MAXMONEY =200*100;  
  17.     /** 
  18.      * 这里为了避免某一个红包占用大量资金,我们需要设定非最后一个红包的最大金额,我们把他设置为红包金额平均值的N倍; 
  19.      */  
  20.     private static final double TIMES =2.1;  
  21.     /** 
  22.      * 拆分红包 
  23.      * @param money :红包总金额 
  24.      * @param count :个数 
  25.      * @return 
  26.      */  
  27.     public List<Integer> splitRedPackets(int money,int count){  
  28.         //红包 合法性校验  
  29.         if(!isRight(money,count)){  
  30.             return null;  
  31.         }  
  32.         //红包列表  
  33.         List<Integer> list =new ArrayList<Integer>();  
  34.         //每个红包最大的金额为平均金额的Times 倍  
  35.         int max =(int)(money*TIMES/count);  
  36.           
  37.         max = max>MAXMONEY ? MAXMONEY : max;  
  38.         //分配红包  
  39.         for (int i = 0; i < count; i++) {  
  40.             int one = randomRedPacket(money,MINMONEY,max,count-i);  
  41.             list.add(one);  
  42.             money -=one;  
  43.         }  
  44.         return list;  
  45.     }  
  46.     /** 
  47.      * 随机分配一个红包 
  48.      * @param money 
  49.      * @param minS :最小金额 
  50.      * @param maxS :最大金额(每个红包的默认Times倍最大值) 
  51.      * @param count 
  52.      * @return 
  53.      */  
  54.     private int randomRedPacket(int money, int minS, int maxS, int count) {  
  55.         //若是只有一个,直接返回红包  
  56.         if(count==1){  
  57.             return money;  
  58.         }  
  59.         //若是最小金额红包 == 最大金额红包, 直接返回最小金额红包  
  60.         if(minS ==maxS){  
  61.             return minS;  
  62.         }  
  63.         //校验 最大值 max 要是比money 金额高的话? 去 money 金额  
  64.         int max = maxS>money ? money : maxS;  
  65.         //随机一个红包 = 随机一个数* (金额-最小)+最小  
  66.         int one =((int)Math.rint(Math.random()*(max-minS)+minS));  
  67.         //剩下的金额  
  68.         int moneyOther =money-one;  
  69.         //校验这种随机方案是否可行,不合法的话,就要重新分配方案  
  70.         if(isRight(moneyOther, count-1)){  
  71.             return one;  
  72.         }else{  
  73.             //重新分配  
  74.             double avg =moneyOther /(count-1);  
  75.             //本次红包过大,导致下次的红包过小;如果红包过大,下次就随机一个小值到本次红包金额的一个红包  
  76.             if(avg<MINMONEY){  
  77.                  //递归调用,修改红包最大金额    
  78.                 return randomRedPacket(money, minS, one, count);  
  79.                   
  80.             }else if(avg>MAXMONEY){  
  81.                  //递归调用,修改红包最小金额    
  82.                 return randomRedPacket(money, one, maxS, count);  
  83.             }  
  84.         }  
  85.         return one;  
  86.     }  
  87.     /** 
  88.      * 红包 合法性校验 
  89.      * @param money 
  90.      * @param count 
  91.      * @return 
  92.      */  
  93.     private boolean isRight(int money, int count) {  
  94.         double avg =money/count;  
  95.         //小于最小金额  
  96.         if(avg<MINMONEY){  
  97.             return false;  
  98.         //大于最大金额      
  99.         }else if(avg>MAXMONEY){  
  100.             return false;  
  101.         }  
  102.         return true;  
  103.     }  
  104.       
  105.     public static void main(String[] args) {  
  106.         //随机一个188.88  5个红包  
  107.         RedEnvelopesDemo dd = new RedEnvelopesDemo();  
  108.         //单位是分  
  109.         System.out.println(dd.splitRedPackets(188885));  
  110.     }  
  111. }  
六、红包分配方案评估

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

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

转自:http://www.llwjy.com/blogdetail/80ad983554a0668be92b5b53a486c55e.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值