本文原创文章,转载注明出处,博客地址 https://segmentfault.com/u/to... 第一时间看后续精彩文章。觉得好的话,顺手分享到朋友圈吧,感谢支持。
普通抽奖问题
问题描述
用户随机抽奖,数据如下:
// map中,key代表用户名,value代表成用户下单数
var users map[string]int64 = map[string]int64{
"a": 10,
"b": 6,
"c": 3,
"d": 12,
"f": 1,
}
思路
随机问题,一般就是通过随机函数从某个范围内随机取出某个数值,则该数值对应的就是中奖用户
在这里,如果我们能给map中每个元素设置对应的索引,即转化为数组,是不是就可以解决问题了呢?
代码实现
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
}
单元测试
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万左右,每个用户的获奖概率相等
c:200102
f:199853
b:198942
a:200395
d:200704
权重抽奖
问题描述:
数据结构和上面抽奖问题一致,只是这里,要求中奖概率和用户的订单数成正比
思路
本质还是随机函数获得一个数值,数值对应的用户即获奖用户;这里要实现订单数对获奖概率的影响问题,即订单数对应随机数的某个范围,订单数越大,范围越大,随机数落在范围内的概率越大
代码实现
func getAwardUser_weight(users map[string]int64) (name string) {
userArr := make([]string, len(users),len(users))
var sumCount int64 = 0
index := 0
for n, c := range users {
//整理所有用户的count数据为数轴
userArr[index] = n
index++
sumCount += c
}
awardIndex := rand.Int63n(sumCount)
var offset int64
for _, n := range userArr {
//判断获奖index落在那个用户区间内
offset += users[n]
if offset > awardIndex {
name = n
return
}
}
return
}
单元测试
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万次,获奖的次数,与用户的订单数成正比
c:93479
f:31206
d:375614
b:186933
a:312764
总结
解决实际问题,往往都有数学模型去对应,比如抽奖问题,就可以转化为初中所学习的数轴知识,画个草图,简单易理解,也不需要多高深的数学知识
问题本身并不难,重要的是转换思路,将抽象问题简化为具体的数学问题,然后去解决
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。