开奖,可以是手动开奖和定时开奖。
抽奖这种活动需要尽可能的公平。
算法分为三个部分:
想到的算法有:
random
shuffle
算法random
此为暴力方法,也是比较容易想到的:随机抽取若干人作为中奖人。
但此问题会产生冲突。
简单步骤如下:
random
一人作为中奖人,加入中奖名单 result
代码如下:
/**
* 获取中奖名单
*
* @param num 奖品数量
* @param participantIds 活动参与者
* @return 中奖名单
*/
private List<String> getWinnerIds(final Integer num, final List<String> participantIds) {
if (num >= participantIds.size()) {
return participantIds;
}
Random random = new Random();
Set<String> userIdSet = new HashSet<>(num);
while (userIdSet.size() < num) {
int index = random.nextInt(participantIds.size());
String userId = participantIds.get(index);
userIdSet.add(userId);
}
return participantIds.subList(0, num);
}
想到以往学过的蓄水池抽样算法,场景乍看一看差不多,都是从一批数据中挑选几个。
但抽样算法主要应用于大数据场景下,所以这边只是简单提一下,有兴趣可以看下下面的链接:
https://crunch.apache.org/apidocs/0.15.0/org/apache/crunch/lib/Sample.html#weightedReservoirSample-org.apache.crunch.PCollection-int-java.lang.Long-
shuffle
算法不就是随机嘛,我把每个都打乱,然后取前面几个作为中奖人即可。
此方法,避免了冲突。
如图:
简单步骤如下:
random
,根据 random
后的数交换位置shuffle
可以直接使用 JDK
提供的 java.util.Collections
。
代码如下:
/**
* 获取中奖名单
*
* @param num 奖品数量
* @param participantIds 活动参与者
* @return 中奖名单
*/
private List<String> getWinnerIds(final Integer num, final List<String> participantIds) {
if (num >= participantIds.size()) {
return participantIds;
}
Collections.shuffle(participantIds);
return participantIds.subList(0, num);
}
在不产出冲突情况下,能再简单嘛?
思路:划分好分区,每个分区抽取一人
如图:
简单步骤如下:
range
),每个分区 random
,这个分区中奖人下标 = random
+ offset
偏移位有个弊端,就是如果奖品数量num
和 活动参与者participantIds
不能整除的话,就会出现其中一个分区的中奖率提升。
代码如下:
/**
* 获取中奖名单
*
* @param num 奖品数量
* @param participantIds 活动参与者
* @return 中奖名单
*/
private List<String> getWinnerIds(final Integer num, final List<String> participantIds) {
if (num >= participantIds.size()) {
return participantIds;
}
int offset = 0;
int range = participantIds.size() / num;
List<Integer> indexList = new ArrayList<>(num);
Random rand = new Random();
for (int i = 0; i < num; ++i) {
int random = rand.nextInt(range);
indexList.add(offset + random);
offset += range;
}
return indexList.stream().map(participantIds::get).collect(Collectors.toList());
}
PS:相比其他几种,更喜欢这种,可操作性高又简单。
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- nryq.cn 版权所有 赣ICP备2024042798号-6
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务