抽奖基本算法讨论

前言

抽奖在我们程序过程中其实是到处可见的,大部分都是直接采用Random进行处理,而这里是针对于多个奖品抽中某一个奖品的概率的一种简单算法-offset

代码如下

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

@Data
public class LotteryTest  {

    public static void main(String[] args) {

        List<Prize> prizeList = new ArrayList<>();

        prizeList.add(new Prize("一等奖", 50));
        prizeList.add(new Prize("二等奖", 30));
        prizeList.add(new Prize("三等奖", 20));

        int lotteryCount = 10000;

        Map<String, Integer> countMap = new LinkedHashMap<>();
        countMap.put("一等奖", 0);
        countMap.put("二等奖", 0);
        countMap.put("三等奖", 0);

        for (int k = 0; k < 30; k++) {
            for (int i = 0; i < lotteryCount; i++) {

                int a = 100;

                for (Prize prize : prizeList) {

                    int r = ThreadLocalRandom.current().nextInt(a);

                    if(r < prize.getL()) {
                        countMap.put(prize.getName(), countMap.get(prize.getName()) + 1);
                        break;
                    }

                    a = a - prize.getL();
                }
            }

            System.out.println(countMap);
            countMap.forEach((t, v) -> {
                countMap.put(t, 0);
            });
        }
    }

    @Data
    @AllArgsConstructor
    static class Prize {

        private String name;
        private int l;
    }
}

运行结果如下

{一等奖=4988, 二等奖=2941, 三等奖=2071}

{一等奖=5087, 二等奖=2924, 三等奖=1989}

{一等奖=5084, 二等奖=2955, 三等奖=1961}

{一等奖=4915, 二等奖=3062, 三等奖=2023}

{一等奖=4975, 二等奖=3105, 三等奖=1920}

{一等奖=4923, 二等奖=3112, 三等奖=1965}

{一等奖=4974, 二等奖=3016, 三等奖=2010}

{一等奖=5016, 二等奖=2989, 三等奖=1995}

{一等奖=4998, 二等奖=3002, 三等奖=2000}

{一等奖=5022, 二等奖=3025, 三等奖=1953}

{一等奖=4979, 二等奖=2975, 三等奖=2046}

{一等奖=5033, 二等奖=2986, 三等奖=1981}

{一等奖=4970, 二等奖=3064, 三等奖=1966}

{一等奖=5005, 二等奖=3067, 三等奖=1928}

{一等奖=4964, 二等奖=3080, 三等奖=1956}

{一等奖=4993, 二等奖=3015, 三等奖=1992}

{一等奖=5106, 二等奖=2915, 三等奖=1979}

{一等奖=5051, 二等奖=2973, 三等奖=1976}

{一等奖=4999, 二等奖=2965, 三等奖=2036}

{一等奖=5076, 二等奖=2966, 三等奖=1958}

{一等奖=5032, 二等奖=2984, 三等奖=1984}

{一等奖=5010, 二等奖=3005, 三等奖=1985}

{一等奖=5019, 二等奖=2947, 三等奖=2034}

{一等奖=5016, 二等奖=2985, 三等奖=1999}

{一等奖=5025, 二等奖=3022, 三等奖=1953}

{一等奖=4912, 二等奖=2998, 三等奖=2090}

{一等奖=5004, 二等奖=2971, 三等奖=2025}

{一等奖=4983, 二等奖=2993, 三等奖=2024}

{一等奖=5087, 二等奖=2870, 三等奖=2043}

{一等奖=5011, 二等奖=2996, 三等奖=1993}

代码核心点介绍

  1. ThreadLocalRandom.current() 为线程安全的随机类

  2. 核心算法在于offset的判断,默认所有奖品的总概率是100,然后循环奖品,如果随机出来的值小于当前奖品则表示中了当前奖品,否则用100减去当前奖品的概率然后再进行抽奖,以此类推,你可以多尝试几次,中奖概率基本是公平的,如上面的例子

一等奖中奖概率为:50%

二等奖中奖概率为:30%

三等奖中奖概率为:20%

扩展点

上面的例子奖品是不存在库存的,假设有库存的存在,那么得根据业务来说是直接不中,还是依次类推,像我之前的就是依次类推,怎么弄呢?思路如下

假设一等奖没有库存了,那么就把一等奖的50%平均分给其他的奖品,也就是说二等奖变为了55%,三等奖变为了45%,然后再进行抽奖

如果你的业务是不允许的话,那么只需要判断中奖时奖品没库存也代表不中就行了

相关推荐
Hcoco_me5 小时前
大模型面试题17:PCA算法详解及入门实操
算法
跨境卫士苏苏5 小时前
亚马逊AI广告革命:告别“猜心”,迎接“共创”时代
大数据·人工智能·算法·亚马逊·防关联
HerayChen6 小时前
HbuilderX 内存溢出报错
java·大数据·linux
程序员小白条6 小时前
0经验如何找实习?
java·开发语言·数据结构·数据库·链表
云雾J视界6 小时前
当算法试图解决一切:技术解决方案主义的诱惑与陷阱
算法·google·bert·transformer·attention·算法治理
Xの哲學6 小时前
Linux Miscdevice深度剖析:从原理到实战的完整指南
linux·服务器·算法·架构·边缘计算
小马爱打代码6 小时前
Spring AI:搭建自定义 MCP Server:获取 QQ 信息
java·人工智能·spring
郭涤生6 小时前
QT 架构笔记
java·数据库·系统架构
daidaidaiyu6 小时前
基于LangGraph开发复杂智能体学习一则
java·ai
夏乌_Wx7 小时前
练题100天——DAY23:存在重复元素Ⅰ Ⅱ+两数之和
数据结构·算法·leetcode