Skip to content

Commit 23ff413

Browse files
committed
+ problem 381
1 parent 4aba22e commit 23ff413

File tree

5 files changed

+224
-0
lines changed

5 files changed

+224
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# 381. Insert Delete GetRandom O(1) - Duplicates allowed
2+
`RandomizedCollection` is a data structure that contains a collection of numbers, possibly duplicates (i.e., a multiset). It should support inserting and removing specific elements and also reporting a random element.
3+
4+
Implement the `RandomizedCollection` class:
5+
* `RandomizedCollection()` Initializes the empty `RandomizedCollection` object.
6+
* `bool insert(int val)` Inserts an item `val` into the multiset, even if the item is already present. Returns `true` if the item is not present, `false` otherwise.
7+
* `bool remove(int val)` Removes an item `val` from the multiset if present. Returns `true` if the item is present, `false` otherwise. Note that if `val` has multiple occurrences in the multiset, we only remove one of them.
8+
* `int getRandom()` Returns a random element from the current multiset of elements. The probability of each element being returned is **linearly related** to the number of the same values the multiset contains.
9+
10+
You must implement the functions of the class such that each function works on **average** `O(1)` time complexity.
11+
12+
**Note:** The test cases are generated such that `getRandom` will only be called if there is **at least one** item in the `RandomizedCollection`.
13+
14+
#### Example 1:
15+
<pre>
16+
<strong>Input:</strong>
17+
["RandomizedCollection", "insert", "insert", "insert", "getRandom", "remove", "getRandom"]
18+
[[], [1], [1], [2], [], [1], []]
19+
<strong>Output:</strong>
20+
[null, true, false, true, 2, true, 1]
21+
<strong>Explanation:</strong>
22+
RandomizedCollection randomizedCollection = new RandomizedCollection();
23+
randomizedCollection.insert(1); // return true since the collection does not contain 1.
24+
// Inserts 1 into the collection.
25+
randomizedCollection.insert(1); // return false since the collection contains 1.
26+
// Inserts another 1 into the collection. Collection now contains [1,1].
27+
randomizedCollection.insert(2); // return true since the collection does not contain 2.
28+
// Inserts 2 into the collection. Collection now contains [1,1,2].
29+
randomizedCollection.getRandom(); // getRandom should:
30+
// - return 1 with probability 2/3, or
31+
// - return 2 with probability 1/3.
32+
randomizedCollection.remove(1); // return true since the collection contains 1.
33+
// Removes 1 from the collection. Collection now contains [1,2].
34+
randomizedCollection.getRandom(); // getRandom should return 1 or 2, both equally likely.
35+
</pre>
36+
37+
#### Constraints:
38+
* <code>-2<sup>31</sup> <= val <= 2<sup>31</sup> - 1</code>
39+
* At most <code>2 * 10<sup>5</sup></code> calls **in total** will be made to `insert`, `remove`, and `getRandom`.
40+
* There will be **at least one** element in the data structure when `getRandom` is called.
41+
42+
## Solutions (Python)
43+
44+
### 1. Solution
45+
```Python
46+
import random
47+
48+
49+
class RandomizedCollection:
50+
51+
def __init__(self):
52+
self.numlist = []
53+
self.numindices = {}
54+
55+
def insert(self, val: int) -> bool:
56+
self.numlist.append(val)
57+
if val not in self.numindices:
58+
self.numindices[val] = set()
59+
self.numindices[val].add(len(self.numlist) - 1)
60+
61+
return len(self.numindices[val]) == 1
62+
63+
def remove(self, val: int) -> bool:
64+
if val not in self.numindices:
65+
return False
66+
67+
i = self.numindices[val].pop()
68+
if len(self.numindices[val]) == 0:
69+
self.numindices.pop(val)
70+
if i == len(self.numlist) - 1:
71+
self.numlist.pop()
72+
else:
73+
self.numlist[i] = self.numlist.pop()
74+
self.numindices[self.numlist[i]].remove(len(self.numlist))
75+
self.numindices[self.numlist[i]].add(i)
76+
77+
return True
78+
79+
def getRandom(self) -> int:
80+
return random.choice(self.numlist)
81+
82+
83+
# Your RandomizedCollection object will be instantiated and called as such:
84+
# obj = RandomizedCollection()
85+
# param_1 = obj.insert(val)
86+
# param_2 = obj.remove(val)
87+
# param_3 = obj.getRandom()
88+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# 381. O(1) 时间插入、删除和获取随机元素 - 允许重复
2+
`RandomizedCollection` 是一种包含数字集合(可能是重复的)的数据结构。它应该支持插入和删除特定元素,以及删除随机元素。
3+
4+
实现 `RandomizedCollection` 类:
5+
* `RandomizedCollection()`初始化空的 `RandomizedCollection` 对象。
6+
* `bool insert(int val)` 将一个 `val` 项插入到集合中,即使该项已经存在。如果该项不存在,则返回 `true` ,否则返回 `false`
7+
* `bool remove(int val)` 如果存在,从集合中移除一个 `val` 项。如果该项存在,则返回 `true` ,否则返回 `false` 。注意,如果 `val` 在集合中出现多次,我们只删除其中一个。
8+
* `int getRandom()` 从当前的多个元素集合中返回一个随机元素。每个元素被返回的概率与集合中包含的相同值的数量 **线性相关**
9+
10+
您必须实现类的函数,使每个函数的 **平均** 时间复杂度为 `O(1)`
11+
12+
**注意:**生成测试用例时,只有在 `RandomizedCollection`**至少有一项** 时,才会调用 `getRandom`
13+
14+
#### 示例 1:
15+
<pre>
16+
<strong>输入:</strong>
17+
["RandomizedCollection", "insert", "insert", "insert", "getRandom", "remove", "getRandom"]
18+
[[], [1], [1], [2], [], [1], []]
19+
<strong>输出:</strong>
20+
[null, true, false, true, 2, true, 1]
21+
<strong>解释:</strong>
22+
RandomizedCollection collection = new RandomizedCollection();// 初始化一个空的集合。
23+
collection.insert(1); // 返回 true,因为集合不包含 1。
24+
// 将 1 插入到集合中。
25+
collection.insert(1); // 返回 false,因为集合包含 1。
26+
// 将另一个 1 插入到集合中。集合现在包含 [1,1]。
27+
collection.insert(2); // 返回 true,因为集合不包含 2。
28+
// 将 2 插入到集合中。集合现在包含 [1,1,2]。
29+
collection.getRandom(); // getRandom 应当:
30+
// 有 2/3 的概率返回 1,
31+
// 1/3 的概率返回 2。
32+
collection.remove(1); // 返回 true,因为集合包含 1。
33+
// 从集合中移除 1。集合现在包含 [1,2]。
34+
collection.getRandom(); // getRandom 应该返回 1 或 2,两者的可能性相同。
35+
</pre>
36+
37+
#### 提示:
38+
* <code>-2<sup>31</sup> <= val <= 2<sup>31</sup> - 1</code>
39+
* `insert`, `remove``getRandom` 最多 **总共** 被调用 <code>2 * 10<sup>5</sup></code> 次
40+
* 当调用 `getRandom` 时,数据结构中 **至少有一个** 元素
41+
42+
## 题解 (Python)
43+
44+
### 1. 题解
45+
```Python
46+
import random
47+
48+
49+
class RandomizedCollection:
50+
51+
def __init__(self):
52+
self.numlist = []
53+
self.numindices = {}
54+
55+
def insert(self, val: int) -> bool:
56+
self.numlist.append(val)
57+
if val not in self.numindices:
58+
self.numindices[val] = set()
59+
self.numindices[val].add(len(self.numlist) - 1)
60+
61+
return len(self.numindices[val]) == 1
62+
63+
def remove(self, val: int) -> bool:
64+
if val not in self.numindices:
65+
return False
66+
67+
i = self.numindices[val].pop()
68+
if len(self.numindices[val]) == 0:
69+
self.numindices.pop(val)
70+
if i == len(self.numlist) - 1:
71+
self.numlist.pop()
72+
else:
73+
self.numlist[i] = self.numlist.pop()
74+
self.numindices[self.numlist[i]].remove(len(self.numlist))
75+
self.numindices[self.numlist[i]].add(i)
76+
77+
return True
78+
79+
def getRandom(self) -> int:
80+
return random.choice(self.numlist)
81+
82+
83+
# Your RandomizedCollection object will be instantiated and called as such:
84+
# obj = RandomizedCollection()
85+
# param_1 = obj.insert(val)
86+
# param_2 = obj.remove(val)
87+
# param_3 = obj.getRandom()
88+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import random
2+
3+
4+
class RandomizedCollection:
5+
6+
def __init__(self):
7+
self.numlist = []
8+
self.numindices = {}
9+
10+
def insert(self, val: int) -> bool:
11+
self.numlist.append(val)
12+
if val not in self.numindices:
13+
self.numindices[val] = set()
14+
self.numindices[val].add(len(self.numlist) - 1)
15+
16+
return len(self.numindices[val]) == 1
17+
18+
def remove(self, val: int) -> bool:
19+
if val not in self.numindices:
20+
return False
21+
22+
i = self.numindices[val].pop()
23+
if len(self.numindices[val]) == 0:
24+
self.numindices.pop(val)
25+
if i == len(self.numlist) - 1:
26+
self.numlist.pop()
27+
else:
28+
self.numlist[i] = self.numlist.pop()
29+
self.numindices[self.numlist[i]].remove(len(self.numlist))
30+
self.numindices[self.numlist[i]].add(i)
31+
32+
return True
33+
34+
def getRandom(self) -> int:
35+
return random.choice(self.numlist)
36+
37+
38+
# Your RandomizedCollection object will be instantiated and called as such:
39+
# obj = RandomizedCollection()
40+
# param_1 = obj.insert(val)
41+
# param_2 = obj.remove(val)
42+
# param_3 = obj.getRandom()

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@
258258
[374][374l] |[Guess Number Higher or Lower][374] |![py]
259259
[375][375l] |[Guess Number Higher or Lower II][375] |![py]
260260
[380][380l] |[Insert Delete GetRandom O(1)][380] |![rs]
261+
[381][381l] |[Insert Delete GetRandom O(1) - Duplicates allowed][381] |![py]
261262
[382][382l] |[Linked List Random Node][382] |![py]
262263
[383][383l] |[Ransom Note][383] |![py]
263264
[384][384l] |[Shuffle an Array][384] |![rs]
@@ -1852,6 +1853,7 @@
18521853
[374]:Problemset/0374-Guess%20Number%20Higher%20or%20Lower/README.md#374-guess-number-higher-or-lower
18531854
[375]:Problemset/0375-Guess%20Number%20Higher%20or%20Lower%20II/README.md#375-guess-number-higher-or-lower-ii
18541855
[380]:Problemset/0380-Insert%20Delete%20GetRandom%20O\(1\)/README.md#380-insert-delete-getrandom-o1
1856+
[381]:Problemset/0381-Insert%20Delete%20GetRandom%20O(1)%20-%20Duplicates%20allowed/README.md#381-insert-delete-getrandom-o1-duplicates-allowed
18551857
[382]:Problemset/0382-Linked%20List%20Random%20Node/README.md#382-linked-list-random-node
18561858
[383]:Problemset/0383-Ransom%20Note/README.md#383-ransom-note
18571859
[384]:Problemset/0384-Shuffle%20an%20Array/README.md#384-shuffle-an-array
@@ -3439,6 +3441,7 @@
34393441
[374l]:https://leetcode.com/problems/guess-number-higher-or-lower/
34403442
[375l]:https://leetcode.com/problems/guess-number-higher-or-lower-ii/
34413443
[380l]:https://leetcode.com/problems/insert-delete-getrandom-o1/
3444+
[381l]:https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/
34423445
[382l]:https://leetcode.com/problems/linked-list-random-node/
34433446
[383l]:https://leetcode.com/problems/ransom-note/
34443447
[384l]:https://leetcode.com/problems/shuffle-an-array/

README_CN.md

+3
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@
258258
[374][374l] |[猜数字大小][374] |![py]
259259
[375][375l] |[猜数字大小 II][375] |![py]
260260
[380][380l] |[O(1) 时间插入、删除和获取随机元素][380] |![rs]
261+
[381][381l] |[O(1) 时间插入、删除和获取随机元素 - 允许重复][381] |![py]
261262
[382][382l] |[链表随机节点][382] |![py]
262263
[383][383l] |[赎金信][383] |![py]
263264
[384][384l] |[打乱数组][384] |![rs]
@@ -1852,6 +1853,7 @@
18521853
[374]:Problemset/0374-Guess%20Number%20Higher%20or%20Lower/README_CN.md#374-猜数字大小
18531854
[375]:Problemset/0375-Guess%20Number%20Higher%20or%20Lower%20II/README_CN.md#375-猜数字大小-ii
18541855
[380]:Problemset/0380-Insert%20Delete%20GetRandom%20O\(1\)/README_CN.md#380-o1-时间插入删除和获取随机元素
1856+
[381]:Problemset/0381-Insert%20Delete%20GetRandom%20O(1)%20-%20Duplicates%20allowed/README_CN.md#381-o1-时间插入、删除和获取随机元素---允许重复
18551857
[382]:Problemset/0382-Linked%20List%20Random%20Node/README_CN.md#382-链表随机节点
18561858
[383]:Problemset/0383-Ransom%20Note/README_CN.md#383-赎金信
18571859
[384]:Problemset/0384-Shuffle%20an%20Array/README_CN.md#384-打乱数组
@@ -3439,6 +3441,7 @@
34393441
[374l]:https://leetcode.cn/problems/guess-number-higher-or-lower/
34403442
[375l]:https://leetcode.cn/problems/guess-number-higher-or-lower-ii/
34413443
[380l]:https://leetcode.cn/problems/insert-delete-getrandom-o1/
3444+
[381l]:https://leetcode.cn/problems/insert-delete-getrandom-o1-duplicates-allowed/
34423445
[382l]:https://leetcode.cn/problems/linked-list-random-node/
34433446
[383l]:https://leetcode.cn/problems/ransom-note/
34443447
[384l]:https://leetcode.cn/problems/shuffle-an-array/

0 commit comments

Comments
 (0)