大转盘抽奖

762 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的12天,点击查看活动详情

大转盘抽奖

​ 抽奖是一种常用的营销工具。抽奖活动产生至今已许多年,一直被各行各业所采用,原因是它契合了人们的消费心理。对消费者而言,“占便宜”是永恒的追求,“以小博大”也满足了顾客追求刺激的心理。而且与其他活动形式相比,大转盘抽奖活动操作简单,趣味性强,满目奖品吸引用户,参与度高,可以刺激沉睡的用户,是促活拉新的不二之选。

转盘抽奖常常用在提交表单,抽奖定向引流。支付完成订单,抽奖给予概率性的奖励,或者定向引流。

抽奖算法

抽奖算法的基本思想是随机一个数,看随机数落在哪个区间。

现有A、B、C三项奖品,概率分别是万分之10,20,30。则谢谢参与D(也作为一个奖项)的概率是10000-10-20-30;

0__ 10 __ 30__60__10000

则获奖区间

A: [0,10]

B: [10,30]

C: [30,60]

D: [60,10000]

random一个0-10000的随机数,落在哪个区间,即中了哪个奖项。

实现代码

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;

/**
 * @author lvzihai
 * @date 2022/4/15
 **/
public class LotteryA {


  private static int draw(){
    int totalCount = 10000;
    int pa = 10;
    int pb = 20;
    int pc = 30;
    // 谢谢参与
    int pd = totalCount -pa-pb-pc;
    int[] gifts = new int[]{pa,pb,pc,pd};

    int[] giftRange = new int[gifts.length];
    int sum = 0;
    for (int i = 0; i < gifts.length; i++) {
      sum+=gifts[i];
      giftRange[i] = sum;
    }
    StrUtil s;

    int randomVal = RandomUtil.randomInt(totalCount);
    for (int i = 0; i < giftRange.length; i++) {
      if(randomVal<giftRange[i]){
        return i;
      }
    }

    return -1;
  }

  public static void main (String[] args) {
    Map<Integer,Integer> map = new HashMap<>();
    int totalCount = 100000;
    for (int i = 0; i < totalCount; i++) {
      int index = draw();
      Integer val = map.get(index);
      val = val==null?1:val+1;
      map.put(index,val);
    }
    // 统计概率 万分之X
    for (Entry<Integer, Integer> entry : map.entrySet()) {
      System.out.println(entry.getKey()+" "+10000.0*entry.getValue()/totalCount);
    }
  }
}

总概率不为1的算法

对于总概率不为1的改进算法。比如概率: A:0.1 B:0.2,C:0.3,D:0.6,将所有概率求和得到总概率,再计算每项的相对概率。

将随机值添加到序列并排序,通过indexOf来获取随机值所在的区间

List<Double> orignalRates = Arrays.asList(0.1,0.2,0.3,0.6);

public static int lottery (List<Double> orignalRates) {
    if (orignalRates == null || orignalRates.isEmpty()) {
      return -1;
    }

    int size = orignalRates.size();

    // 计算总概率,这样可以保证不一定总概率是1
    double sumRate = 0d;
    for (double rate : orignalRates) {
      sumRate += rate;
    }

    // 计算每个物品在总概率的基础下的概率情况
    List<Double> sortOrignalRates = new ArrayList<Double>(size);
    Double tempSumRate = 0d;
    for (double rate : orignalRates) {
      tempSumRate += rate;
      sortOrignalRates.add(tempSumRate / sumRate);
    }

    // 根据区块值来获取抽取到的物品索引
    double nextDouble = Math.random();
    // 将随机值添加到序列并排序,通过indexOf来获取随机值所在的区间
    sortOrignalRates.add(nextDouble);
    Collections.sort(sortOrignalRates);

    return sortOrignalRates.indexOf(nextDouble);
  }
总结

抽奖算法整体思想是把奖项依次排列,谢谢参与也作为一个奖项,排列顺序无关,然后random一个随机数,看随机数落在哪个区间,即哪个奖项。对于有库存的奖项,可以单独计算库存,库存用完,直接返回谢谢参与。