LeetCode 380:Insert Delete GetRandom O(1)

Design a data structure that supports all following operations in average O(1) time.

  1. insert(val): Inserts an item val to the set if not already present.
  2. remove(val): Removes an item val from the set if present.
  3. getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

RandomizedSet randomSet = new RandomizedSet();
// Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomSet.insert(1);
// Returns false as 2 does not exist in the set.
randomSet.remove(2);
// Inserts 2 to the set, returns true. Set now contains [1,2].
randomSet.insert(2);
// getRandom should return either 1 or 2 randomly.
randomSet.getRandom();
// Removes 1 from the set, returns true. Set now contains [2].
randomSet.remove(1);
// 2 was already in the set, so return false.
randomSet.insert(2);
// Since 2 is the only number in the set, getRandom always return 2.
randomSet.getRandom();

Solution

题目要求设计一个插入、删除、取随机值都为 $O(1)$ 的不包含重复值的 Set

使用 ArrayList ,可以实现 $O(1)$ 的插入和取随机值(只需要用 Random 生成一个上界为 size 的索引值就可以取到随机的元素),但是元素是否重复的判断以及获取指定值的操作都需要从头遍历——也就是 $O(n)$ 。

为了避免遍历操作,我们可以用一个 HashMap 来记录元素的值和索引的对应关系。

那么删除操作应该怎么处理呢?我们知道 ArrayList 删除末尾元素不会引起 List 的移动,只需要 $O(1)$ 。因此需要想办法将要删除的元素和最后一个元素作交换。所以只需要用最后的元素覆盖被删除元素(幸好!map 记录了值的索引),然后在 map 中更新元素的新索引,最后删除 map 中被删除元素的记录以及 List 的最后一个元素即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15大专栏  LeetCode 380:Insert Delete GetRandom O(1)pan>
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class  {
ArrayList<Integer> list;
HashMap<Integer, Integer> map;
Random rand;

public () {
list = new ArrayList();
map = new HashMap();
rand = new Random();
}

public boolean insert(int val) {
if (map.containsKey(val)) return false;
list.add(val);
map.put(val, list.size() - 1);
return true;
}

public boolean remove(int val) {
if (!map.containsKey(val)) return false;
// 如果被删除元素不是最后一个元素,需要交换。
if (map.get(val) < list.size() - 1) {
list.set(map.get(val), list.get(list.size()-1));
map.put(list.get(list.size()-1), map.get(val));
}
list.remove(list.size() - 1);
map.remove(val);

return true;
}

public int getRandom() {
return list.get(rand.nextInt(list.size()));
}
}

总结

  • 利用 ArrayList 来保存元素,实现 $O(1)$ 的插入和取随机数。

  • 利用 HashMap 来记录元素和索引的对应关系,避免遍历操作(空间换时间)。

  • 注意在删除的过程中,List 最后的值和被删除值交换,同时要更新 map 的记录。

猜你喜欢

转载自www.cnblogs.com/wangziqiang123/p/11712669.html