Skip to content

Commit 4352b31

Browse files
committed
feat: add solutions to lc problem: No.0380
No.0380.Insert Delete GetRandom O(1)
1 parent 04924f4 commit 4352b31

File tree

6 files changed

+277
-216
lines changed

6 files changed

+277
-216
lines changed

solution/0300-0399/0380.Insert Delete GetRandom O(1)/README.md

Lines changed: 85 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,26 @@ randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom
5757

5858
<!-- 这里可写通用的实现逻辑 -->
5959

60-
哈希表 + 动态列表”实现。
60+
**方法一:哈希表 + 动态列表**
6161

6262
哈希表存放每个元素的值和对应的下标,而动态列表在每个下标位置存放每个元素。由动态列表实现元素的随机返回。
6363

6464
注意,在 `remove()` 实现上,将列表的最后一个元素设置到待删元素的位置上,然后删除最后一个元素,这样在删除元素的时候,不需要挪动一大批元素,从而实现 `O(1)` 时间内操作。
6565

66+
操作细节:
67+
68+
1. **插入**
69+
70+
每次添加新数值时,先使用哈希表判断该数值是否存在,存在则直接返回 false。不存在则进行插入操作,只要将该数值添加到数组尾部即可,并将该数值和其下标的映射存入哈希表。
71+
72+
2. **删除**
73+
74+
删除同样需使用哈希表判断是否存在,若不存在则返回 false。存在则进行删除操作,在哈希表中删除时间复杂度为 O(1),但是在数值中删除比较麻烦。若只是直接删除,则为了保证数组内存连续性需将删除数值后面的数值均前移一位,时间复杂度为 O(n)。比较好的处理方式是,用数组的最后一个数值去填充需要删除的数值的内存,其他数值在数组中的位置保持不变,并将这个拿来填充的数值的下标更新即可,最后只要删除数组最后一个数值,同样可以保证时间复杂度为 O(1)。
75+
76+
3. **随机返回**
77+
78+
只要随机生成数组下标范围内一个随机下标值,返回该数组下标内的数值即可。
79+
6680
<!-- tabs:start -->
6781

6882
### **Python3**
@@ -73,48 +87,36 @@ randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom
7387
class RandomizedSet:
7488

7589
def __init__(self):
76-
"""
77-
Initialize your data structure here.
78-
"""
7990
self.m = {}
8091
self.l = []
8192

8293
def insert(self, val: int) -> bool:
83-
"""
84-
Inserts a value to the set. Returns true if the set did not already contain the specified element.
85-
"""
8694
if val in self.m:
8795
return False
8896
self.m[val] = len(self.l)
8997
self.l.append(val)
9098
return True
9199

92100
def remove(self, val: int) -> bool:
93-
"""
94-
Removes a value from the set. Returns true if the set contained the specified element.
95-
"""
96101
if val not in self.m:
97102
return False
98103
idx = self.m[val]
99-
last_idx = len(self.l) - 1
100-
self.m[self.l[last_idx]] = idx
101-
self.m.pop(val)
102-
self.l[idx] = self.l[last_idx]
104+
self.l[idx] = self.l[-1]
105+
self.m[self.l[-1]] = idx
103106
self.l.pop()
107+
self.m.pop(val)
104108
return True
105109

106110
def getRandom(self) -> int:
107-
"""
108-
Get a random element from the set.
109-
"""
110-
return random.choice(self.l)
111+
return choice(self.l)
111112

112113

113114
# Your RandomizedSet object will be instantiated and called as such:
114115
# obj = RandomizedSet()
115116
# param_1 = obj.insert(val)
116117
# param_2 = obj.remove(val)
117118
# param_3 = obj.getRandom()
119+
118120
```
119121

120122
### **Java**
@@ -123,18 +125,14 @@ class RandomizedSet:
123125

124126
```java
125127
class RandomizedSet {
126-
private Map<Integer, Integer> m;
127-
private List<Integer> l;
128-
private Random rnd;
128+
private Map<Integer, Integer> m = new HashMap<>();
129+
private List<Integer> l = new ArrayList<>();
130+
private Random rnd = new Random();
129131

130-
/** Initialize your data structure here. */
131132
public RandomizedSet() {
132-
m = new HashMap<>();
133-
l = new ArrayList<>();
134-
rnd = new Random();
135-
}
136133

137-
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
134+
}
135+
138136
public boolean insert(int val) {
139137
if (m.containsKey(val)) {
140138
return false;
@@ -143,22 +141,19 @@ class RandomizedSet {
143141
l.add(val);
144142
return true;
145143
}
146-
147-
/** Removes a value from the set. Returns true if the set contained the specified element. */
144+
148145
public boolean remove(int val) {
149146
if (!m.containsKey(val)) {
150147
return false;
151148
}
152149
int idx = m.get(val);
153-
int lastIdx = l.size() - 1;
154-
m.put(l.get(lastIdx), idx);
150+
l.set(idx, l.get(l.size() - 1));
151+
m.put(l.get(l.size() - 1), idx);
152+
l.remove(l.size() - 1);
155153
m.remove(val);
156-
l.set(idx, l.get(lastIdx));
157-
l.remove(lastIdx);
158154
return true;
159155
}
160-
161-
/** Get a random element from the set. */
156+
162157
public int getRandom() {
163158
int idx = rnd.nextInt(l.size());
164159
return l.get(idx);
@@ -176,49 +171,33 @@ class RandomizedSet {
176171

177172
### **C++**
178173

179-
1. 插入
180-
181-
每次添加新数值时,先使用哈希表判断该数值是否存在,存在则直接返回 false。不存在则进行插入操作,只要将该数值添加到数组尾部即可,并将该数值和其下标的映射存入哈希表。
182-
183-
2. 删除
184-
185-
删除同样需使用哈希表判断是否存在,若不存在则返回 false。存在则进行删除操作,在哈希表中删除时间复杂度为 O(1),但是在数值中删除比较麻烦。若只是直接删除,则为了保证数组内存连续性需将删除数值后面的数值均前移一位,时间复杂度为 O(n)。比较好的处理方式是,用数组的最后一个数值去填充需要删除的数值的内存,其他数值在数组中的位置保持不变,并将这个拿来填充的数值的下标更新即可,最后只要删除数组最后一个数值,同样可以保证时间复杂度为 O(1)。
186-
187-
3. 随机返回
188-
189-
只要随机生成数组下标范围内一个随机下标值,返回该数组下标内的数值即可。
190-
191174
```cpp
192175
class RandomizedSet {
176+
private:
193177
unordered_map<int, int> mp;
194178
vector<int> nums;
195179
public:
196180
RandomizedSet() {
197181

198182
}
199-
183+
200184
bool insert(int val) {
201-
if (mp.count(val))
202-
return false;
203-
185+
if (mp.count(val)) return false;
204186
mp[val] = nums.size();
205187
nums.push_back(val);
206188
return true;
207189
}
208-
190+
209191
bool remove(int val) {
210-
if (!mp.count(val))
211-
return false;
212-
213-
int removeIndex = mp[val];
214-
nums[removeIndex] = nums.back();
215-
mp[nums.back()] = removeIndex;
216-
192+
if (!mp.count(val)) return false;
193+
int idx = mp[val];
194+
nums[idx] = nums.back();
195+
mp[nums.back()] = idx;
217196
mp.erase(val);
218197
nums.pop_back();
219198
return true;
220199
}
221-
200+
222201
int getRandom() {
223202
return nums[rand() % nums.size()];
224203
}
@@ -233,6 +212,52 @@ public:
233212
*/
234213
```
235214
215+
### **Go**
216+
217+
```go
218+
type RandomizedSet struct {
219+
m map[int]int
220+
l []int
221+
}
222+
223+
func Constructor() RandomizedSet {
224+
return RandomizedSet{map[int]int{}, []int{}}
225+
}
226+
227+
func (this *RandomizedSet) Insert(val int) bool {
228+
if _, ok := this.m[val]; ok {
229+
return false
230+
}
231+
this.m[val] = len(this.l)
232+
this.l = append(this.l, val)
233+
return true
234+
}
235+
236+
func (this *RandomizedSet) Remove(val int) bool {
237+
if _, ok := this.m[val]; !ok {
238+
return false
239+
}
240+
idx := this.m[val]
241+
this.l[idx] = this.l[len(this.l)-1]
242+
this.m[this.l[len(this.l)-1]] = idx
243+
this.l = this.l[:len(this.l)-1]
244+
delete(this.m, val)
245+
return true
246+
}
247+
248+
func (this *RandomizedSet) GetRandom() int {
249+
return this.l[rand.Intn(len(this.l))]
250+
}
251+
252+
/**
253+
* Your RandomizedSet object will be instantiated and called as such:
254+
* obj := Constructor();
255+
* param_1 := obj.Insert(val);
256+
* param_2 := obj.Remove(val);
257+
* param_3 := obj.GetRandom();
258+
*/
259+
```
260+
236261
### **...**
237262

238263
```

0 commit comments

Comments
 (0)