自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java實現(xiàn)四種微信搶紅包算法,拿走不謝

開發(fā) 后端 算法
14年微信推出紅包功能以后,很多公司開始上自己的紅包功能,到現(xiàn)在為止仍然有很多紅包開發(fā)的需求,實現(xiàn)搶紅包算法也是面試??碱}。

概述

14年微信推出紅包功能以后,很多公司開始上自己的紅包功能,到現(xiàn)在為止仍然有很多紅包開發(fā)的需求,實現(xiàn)搶紅包算法也是面試??碱}。

[[435386]]

要求:

  1. 保證每個紅包最少分得0.01元
  2. 保證每個紅包金額概率盡量均衡
  3. 所有紅包累計金額等于紅包總金額

本文提供4中紅包算法及Java代碼實現(xiàn)demo,僅供參考。其中每種算法測試場景為:0.1元10個包,1元10個包,100元10個包,1000元10個包。

一、剩余金額隨機法

以10元10個紅包為例,去除每個紅包的最小金額后,紅包剩余9.9元;

  1. 第一個紅包在[0,9.9]范圍隨機,假設隨機得1元,則第一個紅包金額為1.1元,紅包剩余8.9元。
  2. 第二個紅包在[0,8.9]范圍隨機,假設隨機得1.5元,則第二個紅包金額為1.6元,紅包剩余7.4元。
  3. 第三個紅包在[0,7.4]范圍隨機,假設隨機得0.5元,則第三個紅包金額為0.6元,紅包剩余6.9元。
  4. 以此類推。 
  1. public static void main(String[] args) { 
  2.     //初始化測試場景 
  3.     BigDecimal[][] rrr = { 
  4.             {new BigDecimal("0.1"), new BigDecimal("10")}, 
  5.             {new BigDecimal("1"), new BigDecimal("10")}, 
  6.             {new BigDecimal("100"), new BigDecimal("10")}, 
  7.             {new BigDecimal("1000"), new BigDecimal("10")} 
  8.     }; 
  9.     BigDecimal min = new BigDecimal("0.01"); 
  10.     //測試個場景 
  11.     for (BigDecimal[] decimals : rrr) { 
  12.         final BigDecimal amount = decimals[0]; 
  13.         final BigDecimal num = decimals[1]; 
  14.         System.out.println(amount + "元" + num + "個人搶======================================================="); 
  15.         test1(amount, min, num); 
  16.     } 
  17.  
  18. private static void test1(BigDecimal amount, BigDecimal min, BigDecimal num) { 
  19.     BigDecimal remain = amount.subtract(min.multiply(num)); 
  20.     final Random random = new Random(); 
  21.     final BigDecimal hundred = new BigDecimal("100"); 
  22.     BigDecimal sum = BigDecimal.ZERO; 
  23.     BigDecimal redpeck; 
  24.     for (int i = 0; i < num.intValue(); i++) { 
  25.         final int nextInt = random.nextInt(100); 
  26.         if (i == num.intValue() - 1) { 
  27.             redpeck = remain; 
  28.         } else { 
  29.             redpeck = new BigDecimal(nextInt).multiply(remain).divide(hundred, 2, RoundingMode.FLOOR); 
  30.         } 
  31.         if (remain.compareTo(redpeck) > 0) { 
  32.             remain = remain.subtract(redpeck); 
  33.         } else { 
  34.             remain = BigDecimal.ZERO; 
  35.         } 
  36.         sum = sum.add(min.add(redpeck)); 
  37.         System.out.println("第" + (i + 1) + "個人搶到紅包金額為:" + min.add(redpeck)); 
  38.     } 
  39.     System.out.println("校驗每個紅包累計額度是否等于紅包總額結果:" + (amount.compareTo(sum) == 0)); 

測試結果如下:可以看出此算法有明顯缺陷,即:先領取的紅包金額較大,后領取的紅包金額較小,這就使得搶紅包變的不公平。 

  1. 0.1元10個人搶======================================================= 
  2. 第1個人搶到紅包金額為:0.01 
  3. 第2個人搶到紅包金額為:0.01 
  4. 第3個人搶到紅包金額為:0.01 
  5. 第4個人搶到紅包金額為:0.01 
  6. 第5個人搶到紅包金額為:0.01 
  7. 第6個人搶到紅包金額為:0.01 
  8. 第7個人搶到紅包金額為:0.01 
  9. 第8個人搶到紅包金額為:0.01 
  10. 第9個人搶到紅包金額為:0.01 
  11. 第10個人搶到紅包金額為:0.01 
  12. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  13. 1元10個人搶======================================================= 
  14. 第1個人搶到紅包金額為:0.09 
  15. 第2個人搶到紅包金額為:0.28 
  16. 第3個人搶到紅包金額為:0.19 
  17. 第4個人搶到紅包金額為:0.20 
  18. 第5個人搶到紅包金額為:0.15 
  19. 第6個人搶到紅包金額為:0.02 
  20. 第7個人搶到紅包金額為:0.03 
  21. 第8個人搶到紅包金額為:0.01 
  22. 第9個人搶到紅包金額為:0.01 
  23. 第10個人搶到紅包金額為:0.02 
  24. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  25. 100元10個人搶======================================================= 
  26. 第1個人搶到紅包金額為:19.99 
  27. 第2個人搶到紅包金額為:29.58 
  28. 第3個人搶到紅包金額為:38.27 
  29. 第4個人搶到紅包金額為:11.85 
  30. 第5個人搶到紅包金額為:0.11 
  31. 第6個人搶到紅包金額為:0.13 
  32. 第7個人搶到紅包金額為:0.01 
  33. 第8個人搶到紅包金額為:0.01 
  34. 第9個人搶到紅包金額為:0.03 
  35. 第10個人搶到紅包金額為:0.02 
  36. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  37. 1000元10個人搶======================================================= 
  38. 第1個人搶到紅包金額為:60.00 
  39. 第2個人搶到紅包金額為:695.54 
  40. 第3個人搶到紅包金額為:229.72 
  41. 第4個人搶到紅包金額為:8.95 
  42. 第5個人搶到紅包金額為:0.29 
  43. 第6個人搶到紅包金額為:4.64 
  44. 第7個人搶到紅包金額為:0.01 
  45. 第8個人搶到紅包金額為:0.69 
  46. 第9個人搶到紅包金額為:0.12 
  47. 第10個人搶到紅包金額為:0.04 
  48. 校驗每個紅包累計額度是否等于紅包總額結果:true 

二、二倍均值法(微信紅包采用此法)

還是以10元10個紅包為例,去除每個紅包的最小金額后,紅包剩余9.9元,二倍均值計算公式:2 * 剩余金額/剩余紅包數(shù)

  1. 第一個紅包在[0,1.98]范圍隨機,假設隨機得1.9,則第一個紅包金額為2.0,紅包剩余8元。
  2. 第二個紅包在[0,2]范圍隨機,假設隨機的1元,則第二個紅包金額為1.1元,紅包剩余7元。
  3. 第三個紅包在[0,2]范圍隨機,假設隨機的0.5元,則第三個紅包金額為0.6元,紅包剩余5.5元。
  4. 以此類推。 
  1. public static void main(String[] args) { 
  2.     //初始化測試場景 
  3.     BigDecimal[][] rrr = { 
  4.             {new BigDecimal("0.1"), new BigDecimal("10")}, 
  5.             {new BigDecimal("1"), new BigDecimal("10")}, 
  6.             {new BigDecimal("100"), new BigDecimal("10")}, 
  7.             {new BigDecimal("1000"), new BigDecimal("10")} 
  8.     }; 
  9.     BigDecimal min = new BigDecimal("0.01"); 
  10.     //測試個場景 
  11.     for (BigDecimal[] decimals : rrr) { 
  12.         final BigDecimal amount = decimals[0]; 
  13.         final BigDecimal num = decimals[1]; 
  14.         System.out.println(amount + "元" + num + "個人搶======================================================="); 
  15.         test2(amount, min, num); 
  16.     } 
  17.  
  18.  
  19. private static void test2(BigDecimal amount,BigDecimal min ,BigDecimal num){ 
  20.     BigDecimal remain = amount.subtract(min.multiply(num)); 
  21.     final Random random = new Random(); 
  22.     final BigDecimal hundred = new BigDecimal("100"); 
  23.     final BigDecimal two = new BigDecimal("2"); 
  24.     BigDecimal sum = BigDecimal.ZERO; 
  25.     BigDecimal redpeck; 
  26.     for (int i = 0; i < num.intValue(); i++) { 
  27.         final int nextInt = random.nextInt(100); 
  28.         if(i == num.intValue() -1){ 
  29.             redpeck = remain; 
  30.         }else
  31.             redpeck = new BigDecimal(nextInt).multiply(remain.multiply(two).divide(num.subtract(new BigDecimal(i)),2,RoundingMode.CEILING)).divide(hundred,2, RoundingMode.FLOOR); 
  32.         } 
  33.         if(remain.compareTo(redpeck) > 0){ 
  34.             remain = remain.subtract(redpeck); 
  35.         }else
  36.             remain = BigDecimal.ZERO; 
  37.         } 
  38.         sum = sum.add(min.add(redpeck)); 
  39.         System.out.println("第"+(i+1)+"個人搶到紅包金額為:"+min.add(redpeck)); 
  40.     } 
  41.     System.out.println("校驗每個紅包累計額度是否等于紅包總額結果:"+amount.compareTo(sum)); 

測試結果如下:此算法很好的保證了搶紅包幾率大致均等。 

  1. 0.1元10個人搶======================================================= 
  2. 第1個人搶到紅包金額為:0.01 
  3. 第2個人搶到紅包金額為:0.01 
  4. 第3個人搶到紅包金額為:0.01 
  5. 第4個人搶到紅包金額為:0.01 
  6. 第5個人搶到紅包金額為:0.01 
  7. 第6個人搶到紅包金額為:0.01 
  8. 第7個人搶到紅包金額為:0.01 
  9. 第8個人搶到紅包金額為:0.01 
  10. 第9個人搶到紅包金額為:0.01 
  11. 第10個人搶到紅包金額為:0.01 
  12. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  13. 100元10個人搶======================================================= 
  14. 第1個人搶到紅包金額為:6.20 
  15. 第2個人搶到紅包金額為:7.09 
  16. 第3個人搶到紅包金額為:10.62 
  17. 第4個人搶到紅包金額為:18.68 
  18. 第5個人搶到紅包金額為:18.74 
  19. 第6個人搶到紅包金額為:2.32 
  20. 第7個人搶到紅包金額為:15.44 
  21. 第8個人搶到紅包金額為:5.43 
  22. 第9個人搶到紅包金額為:15.16 
  23. 第10個人搶到紅包金額為:0.32 
  24. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  25. 1元10個人搶======================================================= 
  26. 第1個人搶到紅包金額為:0.08 
  27. 第2個人搶到紅包金額為:0.05 
  28. 第3個人搶到紅包金額為:0.17 
  29. 第4個人搶到紅包金額為:0.17 
  30. 第5個人搶到紅包金額為:0.08 
  31. 第6個人搶到紅包金額為:0.06 
  32. 第7個人搶到紅包金額為:0.18 
  33. 第8個人搶到紅包金額為:0.10 
  34. 第9個人搶到紅包金額為:0.02 
  35. 第10個人搶到紅包金額為:0.09 
  36. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  37. 1000元10個人搶======================================================= 
  38. 第1個人搶到紅包金額為:125.99 
  39. 第2個人搶到紅包金額為:165.08 
  40. 第3個人搶到紅包金額為:31.90 
  41. 第4個人搶到紅包金額為:94.78 
  42. 第5個人搶到紅包金額為:137.79 
  43. 第6個人搶到紅包金額為:88.89 
  44. 第7個人搶到紅包金額為:156.44 
  45. 第8個人搶到紅包金額為:7.97 
  46. 第9個人搶到紅包金額為:151.01 
  47. 第10個人搶到紅包金額為:40.15 
  48. 校驗每個紅包累計額度是否等于紅包總額結果:true 

三、整體隨機法

還是以10元10個紅包為例,隨機10個數(shù),紅包金額公式為:紅包總額 * 隨機數(shù)/隨機數(shù)總和,假設10個隨機數(shù)為[5,9,8,7,6,5,4,3,2,1],10個隨機數(shù)總和為50,

  1. 第一個紅包10*5/50,得1元。
  2. 第二個紅包10*9/50,得1.8元。
  3. 第三個紅包10*8/50,得1.6元。
  4. 以此類推。 
  1. public static void main(String[] args) { 
  2.     //初始化測試場景 
  3.     BigDecimal[][] rrr = { 
  4.             {new BigDecimal("0.1"), new BigDecimal("10")}, 
  5.             {new BigDecimal("1"), new BigDecimal("10")}, 
  6.             {new BigDecimal("100"), new BigDecimal("10")}, 
  7.             {new BigDecimal("1000"), new BigDecimal("10")} 
  8.     }; 
  9.     BigDecimal min = new BigDecimal("0.01"); 
  10.     //測試個場景 
  11.     for (BigDecimal[] decimals : rrr) { 
  12.         final BigDecimal amount = decimals[0]; 
  13.         final BigDecimal num = decimals[1]; 
  14.         System.out.println(amount + "元" + num + "個人搶======================================================="); 
  15.         test3(amount, min, num); 
  16.     } 
  17.  
  18. private static void test3(BigDecimal amount,BigDecimal min ,BigDecimal num){ 
  19.     final Random random = new Random(); 
  20.     final int[] rand = new int[num.intValue()]; 
  21.     BigDecimal sum1 = BigDecimal.ZERO; 
  22.     BigDecimal redpeck ; 
  23.     int sum = 0; 
  24.     for (int i = 0; i < num.intValue(); i++) { 
  25.         rand[i] = random.nextInt(100); 
  26.         sum += rand[i]; 
  27.     } 
  28.     final BigDecimal bigDecimal = new BigDecimal(sum); 
  29.     BigDecimal remain = amount.subtract(min.multiply(num)); 
  30.     for (int i = 0; i < rand.length; i++) { 
  31.         if(i == num.intValue() -1){ 
  32.             redpeck = remain; 
  33.         }else
  34.             redpeck = remain.multiply(new BigDecimal(rand[i])).divide(bigDecimal,2,RoundingMode.FLOOR); 
  35.         } 
  36.         if(remain.compareTo(redpeck) > 0){ 
  37.             remain = remain.subtract(redpeck); 
  38.         }else
  39.             remain = BigDecimal.ZERO; 
  40.         } 
  41.         sum1= sum1.add(min.add(redpeck)); 
  42.         System.out.println("第"+(i+1)+"個人搶到紅包金額為:"+min.add(redpeck)); 
  43.     } 
  44.  
  45.     System.out.println("校驗每個紅包累計額度是否等于紅包總額結果:"+(amount.compareTo(sum1)==0)); 

測試結果如下:此算法隨機性較大。 

  1. 0.1元10個人搶======================================================= 
  2. 第1個人搶到紅包金額為:0.01 
  3. 第2個人搶到紅包金額為:0.01 
  4. 第3個人搶到紅包金額為:0.01 
  5. 第4個人搶到紅包金額為:0.01 
  6. 第5個人搶到紅包金額為:0.01 
  7. 第6個人搶到紅包金額為:0.01 
  8. 第7個人搶到紅包金額為:0.01 
  9. 第8個人搶到紅包金額為:0.01 
  10. 第9個人搶到紅包金額為:0.01 
  11. 第10個人搶到紅包金額為:0.01 
  12. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  13. 100元10個人搶======================================================= 
  14. 第1個人搶到紅包金額為:2.35 
  15. 第2個人搶到紅包金額為:14.12 
  16. 第3個人搶到紅包金額為:5.74 
  17. 第4個人搶到紅包金額為:6.61 
  18. 第5個人搶到紅包金額為:0.65 
  19. 第6個人搶到紅包金額為:10.97 
  20. 第7個人搶到紅包金額為:9.15 
  21. 第8個人搶到紅包金額為:7.93 
  22. 第9個人搶到紅包金額為:1.31 
  23. 第10個人搶到紅包金額為:41.17 
  24. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  25. 1元10個人搶======================================================= 
  26. 第1個人搶到紅包金額為:0.10 
  27. 第2個人搶到紅包金額為:0.02 
  28. 第3個人搶到紅包金額為:0.12 
  29. 第4個人搶到紅包金額為:0.03 
  30. 第5個人搶到紅包金額為:0.05 
  31. 第6個人搶到紅包金額為:0.12 
  32. 第7個人搶到紅包金額為:0.06 
  33. 第8個人搶到紅包金額為:0.01 
  34. 第9個人搶到紅包金額為:0.04 
  35. 第10個人搶到紅包金額為:0.45 
  36. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  37. 1000元10個人搶======================================================= 
  38. 第1個人搶到紅包金額為:148.96 
  39. 第2個人搶到紅包金額為:116.57 
  40. 第3個人搶到紅包金額為:80.49 
  41. 第4個人搶到紅包金額為:32.48 
  42. 第5個人搶到紅包金額為:89.39 
  43. 第6個人搶到紅包金額為:65.60 
  44. 第7個人搶到紅包金額為:20.77 
  45. 第8個人搶到紅包金額為:16.03 
  46. 第9個人搶到紅包金額為:36.79 
  47. 第10個人搶到紅包金額為:392.92 
  48. 校驗每個紅包累計額度是否等于紅包總額結果:true 

四、割線法

還是以10元10個紅包為例,在(0,10)范圍隨機9個間隔大于等于0.01數(shù),假設為[1,1.2,2,3,4,5,6,7,8]

  1. 第一個紅包得1元
  2. 第二個紅包得0.2元
  3. 第三個紅得0.8元。
  4. 以此類推。 
  1. public static void main(String[] args) { 
  2.     //初始化測試場景 
  3.     BigDecimal[][] rrr = { 
  4.             {new BigDecimal("0.1"), new BigDecimal("10")}, 
  5.             {new BigDecimal("1"), new BigDecimal("10")}, 
  6.             {new BigDecimal("100"), new BigDecimal("10")}, 
  7.             {new BigDecimal("1000"), new BigDecimal("10")} 
  8.     }; 
  9.     BigDecimal min = new BigDecimal("0.01"); 
  10.     //測試個場景 
  11.     for (BigDecimal[] decimals : rrr) { 
  12.         final BigDecimal amount = decimals[0]; 
  13.         final BigDecimal num = decimals[1]; 
  14.         System.out.println(amount + "元" + num + "個人搶======================================================="); 
  15.         test3(amount, min, num); 
  16.     } 
  17.  
  18. private static void test3(BigDecimal amount,BigDecimal min ,BigDecimal num){ 
  19.     final Random random = new Random(); 
  20.     final int[] rand = new int[num.intValue()]; 
  21.     BigDecimal sum1 = BigDecimal.ZERO; 
  22.     BigDecimal redpeck ; 
  23.     int sum = 0; 
  24.     for (int i = 0; i < num.intValue(); i++) { 
  25.         rand[i] = random.nextInt(100); 
  26.         sum += rand[i]; 
  27.     } 
  28.     final BigDecimal bigDecimal = new BigDecimal(sum); 
  29.     BigDecimal remain = amount.subtract(min.multiply(num)); 
  30.     for (int i = 0; i < rand.length; i++) { 
  31.         if(i == num.intValue() -1){ 
  32.             redpeck = remain; 
  33.         }else
  34.             redpeck = remain.multiply(new BigDecimal(rand[i])).divide(bigDecimal,2,RoundingMode.FLOOR); 
  35.         } 
  36.         if(remain.compareTo(redpeck) > 0){ 
  37.             remain = remain.subtract(redpeck); 
  38.         }else
  39.             remain = BigDecimal.ZERO; 
  40.         } 
  41.         sum1= sum1.add(min.add(redpeck)); 
  42.         System.out.println("第"+(i+1)+"個人搶到紅包金額為:"+min.add(redpeck)); 
  43.     } 
  44.  
  45.     System.out.println("校驗每個紅包累計額度是否等于紅包總額結果:"+(amount.compareTo(sum1)==0)); 

測試結果如下:此算法隨機性較大,且性能不好。 

  1. 0.1元10個人搶======================================================= 
  2. 第1個人搶到紅包金額為:0.01 
  3. 第2個人搶到紅包金額為:0.01 
  4. 第3個人搶到紅包金額為:0.01 
  5. 第4個人搶到紅包金額為:0.01 
  6. 第5個人搶到紅包金額為:0.01 
  7. 第6個人搶到紅包金額為:0.01 
  8. 第7個人搶到紅包金額為:0.01 
  9. 第8個人搶到紅包金額為:0.01 
  10. 第9個人搶到紅包金額為:0.01 
  11. 第10個人搶到紅包金額為:0.01 
  12. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  13. 100元10個人搶======================================================= 
  14. 第1個人搶到紅包金額為:19.84 
  15. 第2個人搶到紅包金額為:2.73 
  16. 第3個人搶到紅包金額為:8.95 
  17. 第4個人搶到紅包金額為:14.10 
  18. 第5個人搶到紅包金額為:18.60 
  19. 第6個人搶到紅包金額為:3.66 
  20. 第7個人搶到紅包金額為:9.17 
  21. 第8個人搶到紅包金額為:15.49 
  22. 第9個人搶到紅包金額為:5.61 
  23. 第10個人搶到紅包金額為:1.85 
  24. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  25. 1元10個人搶======================================================= 
  26. 第1個人搶到紅包金額為:0.02 
  27. 第2個人搶到紅包金額為:0.28 
  28. 第3個人搶到紅包金額為:0.03 
  29. 第4個人搶到紅包金額為:0.02 
  30. 第5個人搶到紅包金額為:0.11 
  31. 第6個人搶到紅包金額為:0.23 
  32. 第7個人搶到紅包金額為:0.18 
  33. 第8個人搶到紅包金額為:0.09 
  34. 第9個人搶到紅包金額為:0.03 
  35. 第10個人搶到紅包金額為:0.01 
  36. 校驗每個紅包累計額度是否等于紅包總額結果:true 
  37. 1000元10個人搶======================================================= 
  38. 第1個人搶到紅包金額為:69.28 
  39. 第2個人搶到紅包金額為:14.68 
  40. 第3個人搶到紅包金額為:373.16 
  41. 第4個人搶到紅包金額為:274.73 
  42. 第5個人搶到紅包金額為:30.77 
  43. 第6個人搶到紅包金額為:30.76 
  44. 第7個人搶到紅包金額為:95.55 
  45. 第8個人搶到紅包金額為:85.20 
  46. 第9個人搶到紅包金額為:10.44 
  47. 第10個人搶到紅包金額為:15.43 
  48. 校驗每個紅包累計額度是否等于紅包總額結果:true 

 

 

責任編輯:華軒 來源: 今日頭條
相關推薦

2018-10-18 13:59:36

2022-05-20 08:17:43

Java日志

2015-11-12 09:39:28

微信紅包實現(xiàn)

2024-08-19 11:31:41

2020-05-18 07:50:47

線上故障排查

2015-02-26 14:45:42

微信支付寶紅包

2018-01-31 14:11:31

微信紅包隨機

2020-07-06 10:38:44

辦公軟件工具效率

2018-07-03 16:07:50

2015-02-27 15:19:36

微信紅包算法

2015-03-19 15:13:20

PHP基本排序算法代碼實現(xiàn)

2023-07-11 10:24:00

分布式限流算法

2016-12-23 17:20:56

2018-11-12 10:20:29

網(wǎng)絡安全網(wǎng)絡安全技術周刊

2021-08-11 20:17:22

推薦算法系統(tǒng)

2021-06-24 17:55:40

Python 開發(fā)編程語言

2011-03-16 09:05:53

NATiptables

2021-12-22 09:34:01

Golagn配置方式

2022-05-07 10:14:07

Python數(shù)據(jù)可視化

2009-09-08 17:20:01

C#排序算法
點贊
收藏

51CTO技術棧公眾號