描述

实现 RandomizedSet 类:

  • RandomizedSet() 初始化 RandomizedSet 对象
  • bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false
  • bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false
  • int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。

你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1)

示例

  1. 输入
  2. ["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
  3. [[], [1], [2], [2], [], [1], [2], []]
  4. 输出
  5. [null, true, false, true, 2, true, false, 2]
  6. 解释
  7. RandomizedSet randomizedSet = new RandomizedSet();
  8. randomizedSet.insert(1); // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
  9. randomizedSet.remove(2); // 返回 false ,表示集合中不存在 2 。
  10. randomizedSet.insert(2); // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
  11. randomizedSet.getRandom(); // getRandom 应随机返回 1 或 2 。
  12. randomizedSet.remove(1); // 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
  13. randomizedSet.insert(2); // 2 已在集合中,所以返回 false 。
  14. randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。

提示

  • -231 <= val <= 231 - 1
  • 最多调用 insertremovegetRandom 函数 2 * 105
  • 在调用 getRandom 方法时,数据结构中 至少存在一个 元素。

解题思路

我们需要在平均复杂度为 O(1) 实现以下操作:

  1. insert
  2. remove
  3. getRadom
  • insert 和 getRadom 可以用 arrayList 实现 O(1), 其中,insert 每次在动态数组最后插入。
  • 对于 remove 操作,需要先用一个hashMap 存储动态数组中 值 和 索引 的关系,然后将需要删除的元素与最后一个元素交换,最后删除最后一个元素,实现 O(1)的时间复杂度。
  • 每次操作前判断 hashMap 中是否存在该元素,操作后更新hashMap

代码

  1. class RandomizedSet {
  2. List<Integer> list;
  3. Map<Integer, Integer> dict;
  4. Random rand = new Random();
  5. /** Initialize your data structure here. */
  6. public RandomizedSet() {
  7. list = new ArrayList();
  8. dict = new HashMap();
  9. }
  10. /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
  11. public boolean insert(int val) {
  12. if (dict.containsKey(val)) return false;
  13. dict.put(val, list.size());
  14. list.add(list.size(), val);
  15. return true;
  16. }
  17. /** Removes a value from the set. Returns true if the set contained the specified element. */
  18. public boolean remove(int val) {
  19. if (!dict.containsKey(val)) return false;
  20. int index = dict.get(val);
  21. int tmpVal = list.get(list.size() - 1);
  22. list.set(index, tmpVal);
  23. dict.put(tmpVal, index);
  24. list.remove(list.size() - 1);
  25. dict.remove(val);
  26. return true;
  27. }
  28. /** Get a random element from the set. */
  29. public int getRandom() {
  30. return list.get(rand.nextInt(list.size()));
  31. }
  32. }
  33. /**
  34. * Your RandomizedSet object will be instantiated and called as such:
  35. * RandomizedSet obj = new RandomizedSet();
  36. * boolean param_1 = obj.insert(val);
  37. * boolean param_2 = obj.remove(val);
  38. * int param_3 = obj.getRandom();
  39. */


复杂度分析

时间复杂度:getRandom 时间复杂度为 O(1),insertremove 平均时间复杂度为 O(1),在最坏情况下为 O(N) 当元素数量超过当前分配的动态数组和哈希表的容量导致空间重新分配时。
空间复杂度:O(N),在动态数组和哈希表分别存储了 N 个元素的信息。