本文原創文章,轉載註明出處,部落格地址 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
總結
解決實際問題,往往都有數學模型去對應,比如抽獎問題,就可以轉化為初中所學習的數軸知識,畫個草圖,簡單易理解,也不需要多高深的數學知識
問題本身並不難,重要的是轉換思路,將抽象問題簡化為具體的數學問題,然後去解決