[LeetCode] 380. Insert Delete GetRandom O(1)

Implement the RandomizedSet class:

  • RandomizedSet() Initializes the RandomizedSet object.
  • bool insert(int val) Inserts an item val into the set if not present. Returns true if the item was not present, false otherwise.
  • bool remove(int val) Removes an item val from the set if present. Returns true if the item was present, false otherwise.
  • int getRandom() Returns a random element from the current set of elements (it's guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned.

You must implement the functions of the class such that each function works in average O(1) time complexity.

Example 1:

Input
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
Output
[null, true, false, true, 2, true, false, 2]

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

Constraints:

  • -231 <= val <= 231 - 1
  • At most 2 * 105 calls will be made to insertremove, and getRandom.
  • There will be at least one element in the data structure when getRandom is called.

O(1) 时间插入、删除和获取随机元素。

实现RandomizedSet 类:

RandomizedSet() 初始化 RandomizedSet 对象
bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。
bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false 。
int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。
你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1) 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/insert-delete-getrandom-o1
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题意是设计一个数据结构,满足如下操作的平均时间复杂度为O(1)。我先给代码吧。

Java实现

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

既然是要求 O(1) 的时间复杂度,那么最容易想到的就是 hashmap,不光因为 hashmap 的读取可以达到 O(1),同时因为读取的操作往往找的东西并不是有序的。hashmap 里存的是<元素,他在 list 里的下标>。同时再创建一个 list,因为得到 list size 的时间也接近于 O(1)。

insert 元素的时候,将 val 和当前 list 的 size 当做 key 和 value 加入 hashmap;同时将 val 加入 list,注意此时 list 的 size 跟加入元素的 index 的关系,list 的 size 始终比 index 大 1,因为 index 是从 0 开始的。

remove 的时候,如果这个元素不在 hashmap 自然是 return false,若存在,则把 val 从 hashmap 中移除,同时 map.remove() 函数也能得到当时这个元素在 list 中的 index。如果这个 index 不等于当前 list 的 size 则说明这个要被移除的元素在 list 中不是位于最后一个元素,此时要做的是移除 list 的最后一个元素,并把他覆盖到被移除元素所在的 index 上去。这样才能做到 list 的其他操作为 O(1),而且这里把最后一个元素替换被移除的元素的位置上是不影响最后结果的,这里我们的重点是不要让 list 的相关操作大于 O(1) 的复杂度。

跑一个例子吧,比如一开始加了 1,2,3,4,5 五个数字,他们被加入的时候,hashmap 和 list 应该长类似这样

 1->2->3->4->5

此时如果删除了数字 2,hashmap 和 list 会变成这样,最后一个元素 5 会被覆盖到 list 上 index 为 2 的地方。

 

1->5->3->4

 

相关题目

380. Insert Delete GetRandom O(1)

381. Insert Delete GetRandom O(1) - Duplicates allowed

LeetCode 题目总结

posted @ 2020-04-24 06:39  CNoodle  阅读(194)  评论(0编辑  收藏  举报