|
1 | | -### 380. Insert Delete GetRandom O(1) |
| 1 | +# 380. Insert Delete GetRandom O(1) |
2 | 2 |
|
| 3 | +**<font color=red>难度: Medium</font>** |
3 | 4 |
|
| 5 | +## 刷题内容 |
4 | 6 |
|
5 | | -题目: |
6 | | -<https://leetcode.com/problems/insert-delete-getrandom-o1/> |
| 7 | +> 原题连接 |
7 | 8 |
|
| 9 | +* https://leetcode.com/problems/insert-delete-getrandom-o1/description/ |
8 | 10 |
|
| 11 | +> 内容描述 |
9 | 12 |
|
10 | | -难度 : Hard |
| 13 | +``` |
| 14 | +Design a data structure that supports all following operations in average O(1) time. |
11 | 15 |
|
| 16 | +insert(val): Inserts an item val to the set if not already present. |
| 17 | +remove(val): Removes an item val from the set if present. |
| 18 | +getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned. |
| 19 | +Example: |
12 | 20 |
|
| 21 | +// Init an empty set. |
| 22 | +RandomizedSet randomSet = new RandomizedSet(); |
13 | 23 |
|
14 | | -我的naive TLE代码,关键还是在想这个getRandom,这就不是O(1)的: |
| 24 | +// Inserts 1 to the set. Returns true as 1 was inserted successfully. |
| 25 | +randomSet.insert(1); |
15 | 26 |
|
| 27 | +// Returns false as 2 does not exist in the set. |
| 28 | +randomSet.remove(2); |
16 | 29 |
|
| 30 | +// Inserts 2 to the set, returns true. Set now contains [1,2]. |
| 31 | +randomSet.insert(2); |
17 | 32 |
|
18 | | -``` |
19 | | -class RandomizedSet(object): |
| 33 | +// getRandom should return either 1 or 2 randomly. |
| 34 | +randomSet.getRandom(); |
20 | 35 |
|
21 | | - def __init__(self): |
22 | | - """ |
23 | | - Initialize your data structure here. |
24 | | - """ |
25 | | - self.container = {} |
26 | | - |
| 36 | +// Removes 1 from the set, returns true. Set now contains [2]. |
| 37 | +randomSet.remove(1); |
27 | 38 |
|
28 | | - def insert(self, val): |
29 | | - """ |
30 | | - Inserts a value to the set. Returns true if the set did not already contain the specified element. |
31 | | - :type val: int |
32 | | - :rtype: bool |
33 | | - """ |
34 | | - # 1 stands for present |
35 | | - if val in self.container and self.container[val] == 1: |
36 | | - return False |
37 | | - else: |
38 | | - self.container[val] = 1 |
39 | | - return True |
40 | | - |
| 39 | +// 2 was already in the set, so return false. |
| 40 | +randomSet.insert(2); |
41 | 41 |
|
42 | | - def remove(self, val): |
43 | | - """ |
44 | | - Removes a value from the set. Returns true if the set contained the specified element. |
45 | | - :type val: int |
46 | | - :rtype: bool |
47 | | - """ |
48 | | - if self.container.get(val,0) == 1: |
49 | | - self.container[val] = 0 |
50 | | - return True |
51 | | - else: |
52 | | - return False |
| 42 | +// Since 2 is the only number in the set, getRandom always return 2. |
| 43 | +randomSet.getRandom(); |
| 44 | +``` |
53 | 45 |
|
54 | | - |
| 46 | +## 解题方案 |
55 | 47 |
|
56 | | - def getRandom(self): |
57 | | - """ |
58 | | - Get a random element from the set. |
59 | | - :rtype: int |
60 | | - """ |
61 | | - import random |
62 | | - keys = self.container.keys() |
63 | | - rd = random.randint(0, len(keys) - 1) |
64 | | - if self.container[keys[rd]] == 1: |
65 | | - return keys[rd] |
66 | | - elif self.container.get(keys[rd],0) == 0: |
67 | | - return self.getRandom() |
68 | | -``` |
| 48 | +> 思路 1 |
| 49 | +******- 时间复杂度: O(1)******- 空间复杂度: O(N)****** |
69 | 50 |
|
70 | 51 |
|
71 | 52 |
|
72 | | -也是有[stackoverflow问题界面的题目](http://stackoverflow.com/questions/5682218/data-structure-insert-remove-contains-get-random-element-all-at-o1#comment18171331_5684892): |
| 53 | +因为对于插入,删除还有同可能性返回数都要O(1),我们知道以下几种典型的数据结构 |
| 54 | +``` |
| 55 | +dictionary |
| 56 | +list |
| 57 | +set |
| 58 | +LinkedList |
| 59 | +``` |
| 60 | +想要删除确定数字必须要知道数字的index,所以list肯定需要,然后怎么通过O(1)时间得到要删除元素的index呢? |
| 61 | +就想到用字典,key,value分别是element和其index |
73 | 62 |
|
74 | | -> Consider a data structure composed of a hashtable H and an array A. The hashtable keys are the elements in the data structure, and the values are their positions in the array. |
75 | | -> |
76 | | -> 1.insert(value): append the value to array and let i be its index in A. Set H[value]=i. |
77 | | -> |
78 | | -> 2.remove(value): We are going to replace the cell that contains value in A with the last element in A. let d be the last element in the array A at index m. let i be H[value], the index in the array of the value to be removed. Set A[i]=d, H[d]=i, decrease the size of the array by one, and remove value from H. |
79 | | -> |
80 | | -> 3.contains(value): return H.contains(value) |
81 | | -> |
82 | | -> 4.getRandomElement(): let r=random(current size of A). return A[r]. |
83 | | -> |
84 | | -> |
85 | | -> |
86 | | -> since the array needs to auto-increase in size, it's going to be amortize O(1) to add an element, but I guess that's OK. |
| 63 | +然后想要O(1)时间同可能性返回数都要,必须要知道总共有多少个数字,那么就要维护一个self.length才行 |
87 | 64 |
|
88 | 65 |
|
89 | 66 |
|
90 | 67 |
|
91 | 68 |
|
92 | | -按照以答案AC代码 |
93 | 69 |
|
94 | | -``` |
| 70 | +```python |
| 71 | +import random |
95 | 72 | class RandomizedSet(object): |
96 | 73 |
|
97 | 74 | def __init__(self): |
98 | 75 | """ |
99 | 76 | Initialize your data structure here. |
100 | 77 | """ |
101 | | - self.hashtable = {} |
102 | | - self.array = [] |
103 | | - self.arraySize = 0 |
| 78 | + self.cache = {} |
| 79 | + self.lst = [] |
| 80 | + self.length = 0 |
| 81 | + |
104 | 82 |
|
105 | 83 | def insert(self, val): |
106 | 84 | """ |
107 | 85 | Inserts a value to the set. Returns true if the set did not already contain the specified element. |
108 | 86 | :type val: int |
109 | 87 | :rtype: bool |
110 | 88 | """ |
111 | | - # already in the set |
112 | | - if val in self.hashtable: |
113 | | - return False |
114 | | - else: |
115 | | - self.hashtable[val] = self.arraySize |
116 | | - self.array.append(val) |
117 | | - self.arraySize += 1 |
| 89 | + # if this element is not in our RandomizedSet |
| 90 | + if val not in self.cache: |
| 91 | + # just insert into both of our self.cache and self.lst |
| 92 | + self.cache[val] = self.length |
| 93 | + self.lst.append(val) |
| 94 | + self.length += 1 |
118 | 95 | return True |
119 | | -
|
| 96 | + else: |
| 97 | + return False |
| 98 | + |
120 | 99 |
|
121 | 100 | def remove(self, val): |
122 | 101 | """ |
123 | 102 | Removes a value from the set. Returns true if the set contained the specified element. |
124 | 103 | :type val: int |
125 | 104 | :rtype: bool |
126 | 105 | """ |
127 | | - if val not in self.hashtable: |
128 | | - return False |
129 | | - else: |
130 | | - removeIdx = self.hashtable[val] |
131 | | - if self.arraySize == 1: |
132 | | - self.__init__() |
133 | | - else: |
134 | | - self.array[removeIdx] = self.array[-1] |
135 | | - self.hashtable[self.array[-1]] = removeIdx |
136 | | - self.arraySize -= 1 |
137 | | - del self.hashtable[val] |
138 | | - del self.array[-1] |
| 106 | + # if the elment is in our RandomizedSet |
| 107 | + if val in self.cache: |
| 108 | + # get the index of element in our self.lst |
| 109 | + idx = self.cache[val] |
| 110 | + # use the index to update our self.lst |
| 111 | + self.lst[idx] = self.lst[-1] # swap the value in index and self.length-1 |
| 112 | + # this should be done before pop() operation |
| 113 | + # because we may only have one element is self.lst |
| 114 | + self.cache[self.lst[idx]] = idx |
| 115 | + self.lst.pop() |
| 116 | + del self.cache[val] |
| 117 | + self.length -= 1 |
139 | 118 | return True |
| 119 | + else: |
| 120 | + return False |
140 | 121 |
|
141 | 122 |
|
142 | | -
|
143 | 123 | def getRandom(self): |
144 | 124 | """ |
145 | 125 | Get a random element from the set. |
146 | 126 | :rtype: int |
147 | 127 | """ |
148 | | - import random |
149 | | - rd = random.randint(0, self.arraySize-1) |
150 | | - return self.array[rd] |
151 | | -``` |
152 | | - |
| 128 | + # 这种是常规方法 |
| 129 | + # idx = random.randint(0, self.length-1) |
| 130 | + # return self.lst[idx] |
| 131 | + # 神奇函数 |
| 132 | + return random.choice(self.lst) |
| 133 | + |
153 | 134 |
|
154 | 135 |
|
| 136 | +# Your RandomizedSet object will be instantiated and called as such: |
| 137 | +# obj = RandomizedSet() |
| 138 | +# param_1 = obj.insert(val) |
| 139 | +# param_2 = obj.remove(val) |
| 140 | +# param_3 = obj.getRandom() |
| 141 | +``` |
155 | 142 |
|
156 | 143 |
|
157 | | -最后getRandom也可以写成: |
158 | 144 |
|
159 | | -`return random.choice(self.array)` |
0 commit comments