抽奖算法的具体实现
假设有 奖品A,中奖概率0.1 奖品B,中奖概率0.2 奖品C,中奖概率0.5 未中奖概率,0.2
如何来实现一个抽奖算法。
实现思路
第一时间想到的是构造一个100个数的空间。
抽奖其实就是抽到一个随机数。比如说抽到60,那么就是中了奖品C。抽到20,就是抽到了奖品B。
public class AwardInfo{
public String awardId;
public BigDecimal awaradRate;
}
第一个方法:循环比对
如何确认奖品A就是分布在1-10上呢?
- 将所有奖品包括未中奖的中奖概率加在一起。计算得到中奖的分母因子。
- 将每个奖品的中奖概率除以分母因子乘以100即可。(这里的空间是1000,100000均可)
- 选中一个随机数,进行循环比对即可。
@Override
public String randomDraw(List<AwardInfo> list) {
// 伪代码思路实现
BigDecimal denominator = new BigDecimal(0);
for(AwardInfo elem : list){
denominator = elem.getAwaradRate() + denominator;
}
// 获取一个1-100的随机数
Integer drawNum = getRandomNum(100);
Integer curVal = 0;
String targetAwardId;
for(AwardInfo elem : list){
Integer rateVal = elem.getAwaradRate().divide(denominator, 2, ROUND_UP);
if(drawNum < rateVal + curVal){
targetAwardId = elem.getAwardId();
break;
}
curVal += rateVal;
}
// targetAwardId 就是中奖Id
}
这个算法的弊端在于,时间复杂度会随着奖品池的扩大而扩大。 但其实,我们计算完奖品分布图后,一眼就可以确定中奖的商品。
第二个方法:treemap/hashmap
很简单,只要将奖品信息存储在数据结构中。然后通过fun(drawNum)获取到对应的奖品信息既可以拿到中奖。
- 构造一颗100节点的红黑树/hashmap,每个节点存放奖品Id。
- 通过奖品Id直接拿到节点。
未中奖
对于未中奖,可以理解为抽到了一个特殊奖品。这样有利于统一抽象。