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

来源:互联网 发布:词汇量测试什么软件 编辑:程序博客网 时间:2024/05/16 07:40


转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/50708860

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

个人博客站已经上线了,网址 www.llwjy.com ~欢迎各位吐槽~

-------------------------------------------------------------------------------------------------

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


算法介绍

一、红包金额限制

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

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

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

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

view plaincopy to clipboardprint?
  1. private boolean isRight(int money, int count) {  
  2.     double avg = money / count;  
  3.     if (avg < MINMONEY) {  
  4.         return false;  
  5.     }  
  6.     if (avg > MAXMONEY) {  
  7.         return false;  
  8.     }  
  9.     return true;  
  10. }  

三、随机产生一个红包

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

view plaincopy to clipboardprint?
  1. private int random(int money, int minS, int maxS, int count) {  
  2.     //红包数量为1,直接返回金额  
  3.     if (count == 1) {  
  4.         return money;  
  5.     }  
  6.     //如果最大金额和最小金额相等,直接返回金额  
  7.     if (minS == maxS) {  
  8.         return minS;  
  9.     }  
  10.     int max = maxS > money ? money : maxS;  
  11.     //随机产生一个红包  
  12.     int one = ((int)Math.rint(Math.random() * (max - minS) + minS))  % max + 1;  
  13.     int money1 = money - one;  
  14.     //判断该种分配方案是否正确  
  15.     if (isRight(money1, count -1)) {  
  16.         return one;  
  17.     } else {  
  18.         double avg = money1 / (count - 1);  
  19.         if (avg < MINMONEY) {  
  20.             //递归调用,修改红包最大金额  
  21.             return random(money, minS, one, count);  
  22.         }else if (avg > MAXMONEY) {  
  23.             //递归调用,修改红包最小金额  
  24.             return random(money, one, maxS, count);  
  25.         }  
  26.     }  
  27.     return one;  
  28. }  


第三步优化

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

view plaincopy to clipboardprint?
  1. private int random(int money, int minS, int maxS, int count) {  
  2.     //红包数量为1,直接返回金额  
  3.     if (count == 1) {  
  4.         return money;  
  5.     }  
  6.     //如果最大金额和最小金额相等,直接返回金额  
  7.     if (minS == maxS) {  
  8.         return minS;  
  9.     }  
  10.     int max = maxS > money ? money : maxS;  
  11.     //分配红包正确情况,允许红包的最大值  
  12.     int maxY = money - (count - 1) * minS;  
  13.     //分配红包正确情况,允许红包的最小值  
  14.     int minY = money - (count - 1) * maxS;  
  15.     //随机产生红包的最小值  
  16.     int min = minY > minS ? minY : minS;  
  17.     //随机产生红包最大值  
  18.     max = maxY < max ? maxY : max;  
  19.     //随机产生一个红包  
  20.     return (int)Math.rint(Math.random() * (max - min) + min);  
  21. }  



四、实现红包分配

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

view plaincopy to clipboardprint?
  1. //每个红包最大是平均值的倍数  
  2. private static final double TIMES = 2.1;     
  3.   
  4. public List<Integer> splitRedPackets(int money, int count) {  
  5.     if (!isRight(money, count)) {  
  6.         return null;  
  7.     }  
  8.     List<Integer> list = new ArrayList<Integer>();  
  9.     //红包最大金额为平均金额的TIMES倍  
  10.     int max = (int) (money * TIMES / count);  
  11.     max = max > MAXMONEY ? MAXMONEY : max;  
  12.     for (int i = 0; i < count; i++) {  
  13.         int one = random(money, MINMONEY, max, count - i);  
  14.         list.add(one);  
  15.         money -= one;  
  16.     }  
  17.     return list;  
  18. }  


红包分配方案评估

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

img



完整代码

view plaincopy to clipboardprint?
  1.  /**   
  2.  *@Description:      
  3.  */   
  4. package com.lulei.weixin.util;    
  5.   
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8.   
  9. import com.lulei.util.JsonUtil;  
  10.     
  11. public class RedPacketUtil {  
  12.     //最小红包额度  
  13.     private static final int MINMONEY = 1;  
  14.     //最大红包额度  
  15.     private static final int MAXMONEY = 200 * 100;  
  16.     //每个红包最大是平均值的倍数  
  17.     private static final double TIMES = 2.1;  
  18.       
  19.     /** 
  20.      * @param money 
  21.      * @param count 
  22.      * @return 
  23.      * @Author:lulei   
  24.      * @Description: 拆分红包 
  25.      */  
  26.     public List<Integer> splitRedPackets(int money, int count) {  
  27.         if (!isRight(money, count)) {  
  28.             return null;  
  29.         }  
  30.         List<Integer> list = new ArrayList<Integer>();  
  31.         //红包最大金额为平均金额的TIMES倍  
  32.         int max = (int) (money * TIMES / count);  
  33.         max = max > MAXMONEY ? MAXMONEY : max;  
  34.         for (int i = 0; i < count; i++) {  
  35.             int one = random(money, MINMONEY, max, count - i);  
  36.             list.add(one);  
  37.             money -= one;  
  38.         }  
  39.         return list;  
  40.     }  
  41.       
  42.     /** 
  43.      * @param money 
  44.      * @param minS 
  45.      * @param maxS 
  46.      * @param count 
  47.      * @return 
  48.      * @Author:lulei   
  49.      * @Description: 随机红包额度 
  50.      */  
  51.     private int random(int money, int minS, int maxS, int count) {  
  52.         //红包数量为1,直接返回金额  
  53.         if (count == 1) {  
  54.             return money;  
  55.         }  
  56.         //如果最大金额和最小金额相等,直接返回金额  
  57.         if (minS == maxS) {  
  58.             return minS;  
  59.         }  
  60.         int max = maxS > money ? money : maxS;  
  61.         //随机产生一个红包  
  62.         int one = ((int)Math.rint(Math.random() * (max - minS) + minS))  % max + 1;  
  63.         int money1 = money - one;  
  64.         //判断该种分配方案是否正确  
  65.         if (isRight(money1, count -1)) {  
  66.             return one;  
  67.         } else {  
  68.             double avg = money1 / (count - 1);  
  69.             if (avg < MINMONEY) {  
  70.                 //递归调用,修改红包最大金额  
  71.                 return random(money, minS, one, count);  
  72.             }else if (avg > MAXMONEY) {  
  73.                 //递归调用,修改红包最小金额  
  74.                 return random(money, one, maxS, count);  
  75.             }  
  76.         }  
  77.         return one;  
  78.     }  
  79.       
  80.     /** 
  81.      * @param money 
  82.      * @param count 
  83.      * @return 
  84.      * @Author:lulei   
  85.      * @Description: 此种红包是否合法 
  86.      */  
  87.     private boolean isRight(int money, int count) {  
  88.         double avg = money / count;  
  89.         if (avg < MINMONEY) {  
  90.             return false;  
  91.         }  
  92.         if (avg > MAXMONEY) {  
  93.             return false;  
  94.         }  
  95.         return true;  
  96.     }  
  97.   
  98.     public static void main(String[] args) {  
  99.         // TODO Auto-generated method stub    
  100.         RedPacketUtil util = new RedPacketUtil();  
  101.         System.out.println(JsonUtil.parseJson(util.splitRedPackets(20000100)));  
  102.     }  
  103. }  


-------------------------------------------------------------------------------------------------
小福利
-------------------------------------------------------------------------------------------------
      个人在极客学院上《Lucene案例开发》课程已经上线了,欢迎大家吐槽~

第一课:Lucene概述

第二课:Lucene 常用功能介绍

第三课:网络爬虫

第四课:数据库连接池

第五课:小说网站的采集

第六课:小说网站数据库操作

第七课:小说网站分布式爬虫的实现

第八课:Lucene实时搜索

  • © 版权所有,转载请注明出处:http://www.llwjy.com/blogdetail/80ad983554a0668be92b5b53a486c55e.html
  • 上一篇:JAVA实现将GeoHash转化为对应的经纬度坐标
  • 下一篇:北京丁丁租房招聘JAVA开发人员

0 0
原创粉丝点击