美文网首页
抽奖问题分析

抽奖问题分析

作者: TomorrowWu | 来源:发表于2017-09-05 15:36 被阅读0次

    普通抽奖问题

    问题描述

    用户随机抽奖,数据如下:

    // 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) {
        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
    }
    

    单元测试

    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 
    

    总结

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

    image.png

    相关文章

      网友评论

          本文标题:抽奖问题分析

          本文链接:https://www.haomeiwen.com/subject/udnujxtx.html