首页 > 技术文章 > [LeetCode] 380. Insert Delete GetRandom O(1)

cnoodle 2020-04-24 06:39 原文

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

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

Example:

// Init an empty set.
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();

常数时间插入、删除和获取随机元素。题意是设计一个数据结构,满足如下操作的平均时间复杂度为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)。同时再创建一个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的最后一个元素,并把他覆盖到被移除元素所在的index上去。这样才能做到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 题目总结

推荐阅读