docs(note): 添加笔记目录及 gitignore 规则
- 新增 note 目录包含 AI、SQL、Golang、网络等多领域学习笔记 - 更新 .gitignore 添加 note/assets/ 和 note/项目/ 忽略规则
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
## 权重抽奖
|
||||
|
||||
### 轮盘赌
|
||||
|
||||
适合奖品数量较少,一次性抽奖的场景
|
||||
|
||||
核心顺序遍历,逐个减权重:是用一个随机数 `r`,依次减去每个奖品的权重,当 `r` 变成负数的那一刻,说明它“落入了”当前奖品的权重区间。时间复杂度 **O(n)**,空间复杂度**O(1)**
|
||||
|
||||
```go
|
||||
func Draw(rewards []*Reward) *Reward {
|
||||
totalWeight := 0
|
||||
for _, r := range rewards {
|
||||
totalWeight += r.Weight
|
||||
}
|
||||
r := rand.Intn(totalWeight) // [0, totalWeight)
|
||||
for _, reward := range rewards {
|
||||
r -= reward.Weight
|
||||
if r < 0 {
|
||||
return reward
|
||||
}
|
||||
}
|
||||
return rewards[len(rewards)-1] // 兜底,理论上不会走到
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 前缀和 + 二分查找
|
||||
|
||||
适合奖品数量较多,需要频繁抽奖的通用场景
|
||||
|
||||
核心是构建前缀和数组,二分查找:把权重想象成一条线段,每个奖品占据一段,生成 `[0, 100)` 的随机数,落在哪个区间就中哪个奖品。二分查找快速定位区间,时间复杂度 **O(log n)**,空间复杂度**O(n)**
|
||||
|
||||
```
|
||||
权重: 50 25 15 7 2 1
|
||||
├─────────┼────────┼──────┼────┼──┼──┤
|
||||
0 50 75 90 97 99 100
|
||||
← 谢谢参与 →←5元券→←10元券→←月卡→←年卡→←大奖→
|
||||
```
|
||||
|
||||
```go
|
||||
type Reward struct {
|
||||
Name string
|
||||
Weight int
|
||||
}
|
||||
|
||||
func Draw(rewards []*Reward) *Reward {
|
||||
prefixSumArray := make([]int, len(rewards)) // 前缀和数组
|
||||
totalWeight := 0 // 总权重
|
||||
for i, p := range rewards {
|
||||
totalWeight += p.Weight
|
||||
prefixSumArray[i] = totalWeight
|
||||
fmt.Println(totalWeight)
|
||||
}
|
||||
r := rand.Intn(totalWeight) // r ∈ [0, totalWeight-1]
|
||||
idx := sort.SearchInts(prefixSumArray, r+1) // 查找目标 ∈ [1, totalWeight]
|
||||
return rewards[idx]
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user