LeetCode 0381. O 时间插入删除和获取随机元素 - 允许重复
Posted Tisfy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 0381. O 时间插入删除和获取随机元素 - 允许重复相关的知识,希望对你有一定的参考价值。
【LetMeFly】STL的应用:381.O(1) 时间插入、删除和获取随机元素 - 允许重复
力扣题目链接:https://leetcode.cn/problems/insert-delete-getrandom-o1-duplicates-allowed/
RandomizedCollection
是一种包含数字集合(可能是重复的)的数据结构。它应该支持插入和删除特定元素,以及删除随机元素。
实现 RandomizedCollection
类:
RandomizedCollection()
初始化空的RandomizedCollection
对象。bool insert(int val)
将一个val
项插入到集合中,即使该项已经存在。如果该项不存在,则返回true
,否则返回false
。bool remove(int val)
如果存在,从集合中移除一个val
项。如果该项存在,则返回true
,否则返回false
。注意,如果val
在集合中出现多次,我们只删除其中一个。int getRandom()
从当前的多个元素集合中返回一个随机元素。每个元素被返回的概率与集合中包含的相同值的数量 线性相关 。
您必须实现类的函数,使每个函数的 平均 时间复杂度为 O(1)
。
注意:生成测试用例时,只有在 RandomizedCollection
中 至少有一项 时,才会调用 getRandom
。
示例 1:
输入 ["RandomizedCollection", "insert", "insert", "insert", "getRandom", "remove", "getRandom"] [[], [1], [1], [2], [], [1], []] 输出 [null, true, false, true, 2, true, 1] 解释 RandomizedCollection collection = new RandomizedCollection();// 初始化一个空的集合。 collection.insert(1);// 向集合中插入 1 。返回 true 表示集合不包含 1 。 collection.insert(1);// 向集合中插入另一个 1 。返回 false 表示集合包含 1 。集合现在包含 [1,1] 。 collection.insert(2);// 向集合中插入 2 ,返回 true 。集合现在包含 [1,1,2] 。 collection.getRandom();// getRandom 应当有 2/3 的概率返回 1 ,1/3 的概率返回 2 。 collection.remove(1);// 从集合中删除 1 ,返回 true 。集合现在包含 [1,2] 。 collection.getRandom();// getRandom 应有相同概率返回 1 和 2 。
提示:
-231 <= val <= 231 - 1
insert
,remove
和getRandom
最多 总共 被调用2 * 105
次- 当调用
getRandom
时,数据结构中 至少有一个 元素
方法一:STL的灵活运用
本题考查对STL的灵活运用。
如果使用STL,那么插入删除操作都很容易完成。
但是如果想要在 O ( 1 ) O(1) O(1)时间内返回随机值,想使用STL就不是那么容易了。
数组中返回一个随机值很容易,时间复杂度是 O ( 1 ) O(1) O(1),插入数据也很容易,只是删除数据有点麻烦(一是难以找到待删除的数据在哪里,二是删除中间的数据的时间复杂度并不是 O ( 1 ) O(1) O(1))
因此,我们可以把以上两者结合起来:
- 既然数组中难以找到值为
val
的元素的下标,那么我们就用哈希表把值为val
的元素的下标存起来 - 既然删除中间元素耗时交长,那么我们不删除中间的元素,二是把中间的元素和末尾的元素进行交换,再删除末尾的元素
好了,目的明确,开始搞事情
我们很容易使用哈希表来存放某个元素在数组中的下标。比如unordered_map<int, int>
但由于元素可能重复,因此改成使用unordered_map<int, unordered_set<int>>
至于为什么不使用unordered_multimap<int, int>
,是因为unordered_multimap<int, int>
难以在
O
(
1
)
O(1)
O(1)的时间内删除指定键值对pair<int, int>
具体可见代码注释。
- 单次操作时间复杂度 O ( 1 ) O(1) O(1)。虽为 O ( 1 ) O(1) O(1),但是时间复杂度常数特别大。
- 空间复杂度 O ( n ) O(n) O(n)
AC代码
C++
class RandomizedCollection
private:
unordered_map<int, unordered_set<int>> ma; // <val, [locOfThisVal]>
vector<int> a;
public:
RandomizedCollection()
bool insert(int val) // 插入并返回插入前是否无此数
ma[val].insert(a.size());
a.push_back(val);
return ma[val].size() == 1;
bool remove(int val)
if (!ma.count(val)) // 不存在次数
return false;
// erase掉这个数
unordered_set<int>::iterator it = ma[val].begin();
int index = *it;
ma[val].erase(it);
if (ma[val].empty())
ma.erase(val);
// 如果这个数在数组中不是最后一个元素,那么就需要将其与最后一个元素交换,再将最后一个元素删除
if (index < a.size() - 1)
int index2swap = a.size() - 1;
a[index] = a[index2swap];
// 更新最后一个元素的下标
ma[a[index2swap]].erase(index2swap);
ma[a[index2swap]].insert(index);
a.pop_back();
return true;
int getRandom()
return a[rand() % a.size()];
;
同步发文于CSDN,原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/127262069
以上是关于LeetCode 0381. O 时间插入删除和获取随机元素 - 允许重复的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 380 O时间插入删除和获取随机元素[Map 数组] HERODING的LeetCode之路
[leetcode]380. Insert Delete GetRandom O常数时间插入删除取随机值
LeetCode 380. Insert Delete GetRandom O (插入删除和获得随机数 常数时间)
LeetCode 381. Insert Delete GetRandom O - Duplicates allowed (插入删除和获得随机数 常数时间 允许重复项)