题目
设计一个支持在平均 时间复杂度 下,执行以下操作的数据结构。
insert(val)
:当元素 val 不存在时,向集合中插入该项。remove(val)
:元素 val 存在时,从集合中移除该项。getRandom
:随机返回现有集合中的一项。每个元素应该有相同的概率被返回。
示例 :
// 初始化一个空的集合。
RandomizedSet randomSet = new RandomizedSet();
// 向集合中插入 1 。返回 true 表示 1 被成功地插入。
randomSet.insert(1);
// 返回 false ,表示集合中不存在 2 。
randomSet.remove(2);
// 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
randomSet.insert(2);
// getRandom 应随机返回 1 或 2 。
randomSet.getRandom();
// 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
randomSet.remove(1);
// 2 已在集合中,所以返回 false 。
randomSet.insert(2);
// 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。
randomSet.getRandom();
方案一
type RandomizedSet struct {
m map[int]int
}
/** Initialize your data structure here. */
func Constructor() RandomizedSet {
return RandomizedSet {
m: map[int]int{},
}
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
func (this *RandomizedSet) Insert(val int) bool {
if _, ok := this.m[val]; ok {
return false
}
this.m[val] = 0
return true
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
func (this *RandomizedSet) Remove(val int) bool {
if _, ok := this.m[val]; !ok {
return false
}
delete(this.m, val)
return true
}
/** Get a random element from the set. */
func (this *RandomizedSet) GetRandom() int {
keys := []int{}
for k, _ := range this.m {
keys = append(keys, k)
}
return keys[rand.Intn(len(keys))]
}
- 上述方案获取随机值时间复杂度为
方案二
type RandomizedSet struct {
list []int
m map[int]int // value: list index -> 让我想到了 lru的实现,即使用 map + 双向链表的思路
}
/** Initialize your data structure here. */
func Constructor() RandomizedSet {
return RandomizedSet {
list: []int{},
m: map[int]int{}, // key: val, value: 对应 list 的 index
}
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
func (this *RandomizedSet) Insert(val int) bool {
if _, ok := this.m[val]; ok {
return false
}
this.m[val] = len(this.list)
this.list = append(this.list, val)
return true
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
func (this *RandomizedSet) Remove(val int) bool {
index, ok := this.m[val]
if !ok {
return false
}
if index != len(this.list) - 1 { // 删除的不是数组的最后一个;这时为了防止删除导致数组元素移动以及 this.m 索引问题,采用交换的策略
last := this.list[len(this.list) - 1]
this.list[index] = last
this.m[last] = index
}
// 删除数组最后一个元素
this.list = this.list[:len(this.list) - 1]
delete(this.m, val)
return true
}
/** Get a random element from the set. */
func (this *RandomizedSet) GetRandom() int {
return this.list[rand.Intn(len(this.list))]
}
- 使用一个
map
来存储实际数据的指针,同时使用另一个列表来存储实际数据 - 注意
Remove
方法采取的方案。——交换,避免不必要的元素移动
原文
https://leetcode-cn.com/explore/learn/card/hash-table/207/conclusion/831/