抽奖问题分析

2025-07-12 15:13:44

普通抽奖问题问题描述用户随机抽奖,数据如下:

代码语言:javascript代码运行次数:0运行复制// map中,key代表用户名,value代表成用户下单数

var users map[string]int64 = map[string]int64{

"a": 10,

"b": 6,

"c": 3,

"d": 12,

"f": 1,

}

思路

随机问题,一般就是通过随机函数从某个范围内随机取出某个数值,则该数值对应的就是中奖用户

在这里,如果我们能给map中每个元素设置对应的索引,即转化为数组,是不是就可以解决问题了呢?

代码实现

代码语言:javascript代码运行次数:0运行复制func GetAwardUserName(users map[string]int64) (name string) {

size := len(users)

awardIndex := rand.Intn(size)

i := 0

for userName, _ := range users {

if i == awardIndex {

name = userName

return

}

i++

}

return

}

单元测试

代码语言:javascript代码运行次数:0运行复制func Test_GetAwardUserName(t *testing.T) {

var users map[string]int64 = map[string]int64{

"a": 10,

"b": 6,

"c": 3,

"d": 12,

"f": 1,

}

rand.Seed(time.Now().Unix())

awardCount := make(map[string]int)

for i := 0; i <= 1000000; i++ {

awardName := GetAwardUserName(users)

if count, ok := awardCount[awardName]; ok {

awardCount[awardName] = count + 1

} else {

awardCount[awardName] = 0

}

}

for n, c := range awardCount {

fmt.Printf("%v:%v\n",n,c)

}

}

测试结果:

为了验证获奖概率的正确性,循环执行100万次,每个用户获奖的次数基本在20万左右,每个用户的获奖概率相等

代码语言:javascript代码运行次数:0运行复制c:200102

f:199853

b:198942

a:200395

d:200704

权重抽奖问题描述:

数据结构和上面抽奖问题一致,只是这里,要求中奖概率和用户的订单数成正比

思路

==本质==还是随机函数获得一个数值,数值对应的用户即获奖用户;这里要实现订单数对获奖概率的影响问题,即==订单数对应随机数的某个范围,订单数越大,范围越大,随机数落在范围内的概率越大==

代码实现

代码语言:javascript代码运行次数:0运行复制func getAwardUser_weight(users map[string]int64) (name string) {

type awardUser struct {

name string

offset int64

count int64

}

userSli := make([]*awardUser, 0,len(users))

var sumCount int64 = 0

for n, c := range users {

a := awardUser{

name: n,

offset: sumCount,

count: c,

}

//整理所有用户的count数据为数轴

userSli = append(userSli, &a)

sumCount += c

}

awardIndex := rand.Int63n(sumCount)

for _, u := range userSli {

//判断获奖index落在那个用户区间内

if u.offset+u.count>awardIndex {

name = u.name

return

}

}

return

}

单元测试

代码语言:javascript代码运行次数:0运行复制func Test_getAwardUser_weight(t *testing.T) {

var users map[string]int64 = map[string]int64{

"a": 10,

"b": 6,

"c": 3,

"d": 12,

"f": 1,

}

rand.Seed(time.Now().Unix())

awardCount := make(map[string]int)

for i := 0; i <= 100000; i++ {

awardName := getAwardUser_weight(users)

if count, ok := awardCount[awardName]; ok {

awardCount[awardName] = count + 1

} else {

awardCount[awardName] = 0

}

}

for n,c := range awardCount {

fmt.Printf("%v:%v \n",n,c)

}

}

测试结果:

循环遍历了100万次,获奖的次数,与用户的订单数成正比

代码语言:javascript代码运行次数:0运行复制c:93479

f:31206

d:375614

b:186933

a:312764总结

解决实际问题,往往都有数学模型去对应,比如抽奖问题,就可以转化为初中所学习的数轴知识,画个草图,简单易理解,也不需要多高深的数学知识

问题本身并不难,重要的是转换思路,将抽象问题简化为具体的数学问题,然后去解决