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

Note: Duplicate elements are allowed.

  1. insert(val): Inserts an item val to the collection.
  2. remove(val): Removes an item val from the collection if present.
  3. getRandom: Returns a random element from current collection of elements. The probability of each element being returned is linearly related to the number of same value the collection contains.

Example:

// Init an empty collection.
RandomizedCollection collection = new RandomizedCollection(); // Inserts 1 to the collection. Returns true as the collection did not contain 1.
collection.insert(1); // Inserts another 1 to the collection. Returns false as the collection contained 1. Collection now contains [1,1].
collection.insert(1); // Inserts 2 to the collection, returns true. Collection now contains [1,1,2].
collection.insert(2); // getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3.
collection.getRandom(); // Removes 1 from the collection, returns true. Collection now contains [1,2].
collection.remove(1); // getRandom should return 1 and 2 both equally likely.
collection.getRandom();

这题是之前那道 Insert Delete GetRandom O(1) 的拓展,与其不同的是,之前那道题不能有重复数字,而这道题可以有,那么就不能像之前那道题那样建立每个数字和其坐标的映射了,但是我们可以建立数字和其所有出现位置的集合之间的映射,虽然写法略有不同,但是思路和之前那题完全一样,都是将数组最后一个位置的元素和要删除的元素交换位置,然后删掉最后一个位置上的元素。对于 insert 函数,我们将要插入的数字在 nums 中的位置加入 m[val] 数组的末尾,然后在数组 nums 末尾加入 val,我们判断是否有重复只要看 m[val] 数组只有刚加的 val 一个值还是有多个值。remove 函数是这题的难点,我们首先看 HashMap 中有没有 val,没有的话直接返回 false。然后我们取出 nums 的尾元素,把尾元素 HashMap 中的位置数组中的最后一个位置更新为 m[val] 的尾元素,这样我们就可以删掉 m[val] 的尾元素了,如果 m[val] 只有一个元素,那么我们把这个映射直接删除。然后将 nums 数组中的尾元素删除,并把尾元素赋给 val 所在的位置,注意我们在建立 HashMap 的映射的时候需要用堆而不是普通的 vector 数组,因为我们每次 remove 操作后都会移除 nums 数组的尾元素,如果我们用 vector 来保存数字的坐标,而且只移出末尾数字的话,有可能出现前面的坐标大小超过了此时 nums 的大小的情况,就会出错,所以我们用优先队列对所有的相同数字的坐标进行自动排序,每次把最大位置的坐标移出即可,参见代码如下:

解法一:

class RandomizedCollection {
public:
RandomizedCollection() {}
bool insert(int val) {
m[val].push(nums.size());
nums.push_back(val);
return m[val].size() == ;
}
bool remove(int val) {
if (m[val].empty()) return false;
int idx = m[val].top();
m[val].pop();
if (nums.size() - != idx) {
int t = nums.back();
nums[idx] = t;
m[t].pop();
m[t].push(idx);
}
nums.pop_back();
return true;
}
int getRandom() {
return nums[rand() % nums.size()];
}
private:
vector<int> nums;
unordered_map<int, priority_queue<int>> m;
};

有网友指出上面的方法其实不是真正的 O(1) 时间复杂度,因为优先队列的 push 不是常数级的,博主一看果然是这样的,为了严格的遵守 O(1) 的时间复杂度,我们将优先队列换成 unordered_set,其插入删除的操作都是常数量级的,其他部分基本不用变,参见代码如下:

解法二:

class RandomizedCollection {
public:
RandomizedCollection() {}
bool insert(int val) {
m[val].insert(nums.size());
nums.push_back(val);
return m[val].size() == ;
}
bool remove(int val) {
if (m[val].empty()) return false;
int idx = *m[val].begin();
m[val].erase(idx);
if (nums.size() - != idx) {
int t = nums.back();
nums[idx] = t;
m[t].erase(nums.size() - );
m[t].insert(idx);
}
nums.pop_back();
return true;
}
int getRandom() {
return nums[rand() % nums.size()];
} private:
vector<int> nums;
unordered_map<int, unordered_set<int>> m;
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/381

类似题目:

Insert Delete GetRandom O(1)

参考资料:

https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/

https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/discuss/85635/c-two-solutions

https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/discuss/85541/C%2B%2B-128m-Solution-Real-O(1)-Solution

https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/discuss/197641/C%2B%2B-30-ms-hashmap-hashset-and-vector

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 381. Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复的更多相关文章

  1. [LeetCode] Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复

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

  2. [leetcode]381. Insert Delete GetRandom O(1) - Duplicates allowed常数时间插入删除取随机值

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

  3. [LeetCode] 381. Insert Delete GetRandom O(1) - Duplicates allowed 插入删除和获得随机数O(1)时间 - 允许重复

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

  4. LeetCode 381. Insert Delete GetRandom O(1) - Duplicates allowed O(1) 时间插入、删除和获取随机元素 - 允许重复(C++/Java)

    题目: Design a data structure that supports all following operations in averageO(1) time. Note: Duplic ...

  5. LeetCode 381. Insert Delete GetRandom O(1) - Duplicates allowed

    原题链接在这里:https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/?tab=Description ...

  6. LeetCode 381. Insert Delete GetRandom O(1) - Duplicates allowed (插入删除和获得随机数 常数时间 允许重复项)

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

  7. leetcode 380. Insert Delete GetRandom O(1) 、381. Insert Delete GetRandom O(1) - Duplicates allowed

    380. Insert Delete GetRandom O(1) 实现插入.删除.获得随机数功能,且时间复杂度都在O(1).实际上在插入.删除两个功能中都包含了查找功能,当然查找也必须是O(1). ...

  8. 381. Insert Delete GetRandom O(1) - Duplicates allowed

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

  9. 381 Insert Delete GetRandom O(1) - Duplicates allowed O(1) 时间插入、删除和获取随机元素 - 允许重复

    设计一个支持在平均 时间复杂度 O(1) 下, 执行以下操作的数据结构.注意: 允许出现重复元素.    insert(val):向集合中插入元素 val.    remove(val):当 val ...

随机推荐

  1. 查看xml源码的方法

    查看xml源码的方法 要通过查看源码才能看到xml源码 因为 print_r输出的时候 默认页面打开是html编码的...... 所以解析不了xml

  2. Module Code: CMT107

    Cardiff School of Computer Science and InformaticsCoursework Assessment Pro-formaModule Code: CMT107 ...

  3. 使用wireshark学习TCP

    TCP标志位: 在TCP传输中,标志位用于表示特定的连接状态或提供额外信息.每个标志位占用1比特.常用的TCP标志位包含以下几种: SYN Synchronous,TCP三次握手建立连接的第一步,主动 ...

  4. S-T-E-A-M Science Technology Engineering Art Mathematics 五种思维模式

    S-T-E-A-M五个英文字母分别代表 Science 科学,Technology 技术,Engineering 工程,Art 艺术以及 Mathematics 数学.它们并不是简单地整合原来的分科体 ...

  5. [ICP]手推SVD方法

    该方法源于<Least-Squares Rigid Motion Using SVD>,原文推导十分详细,这里自己也仔细推导了一遍,有些地方加以注释整理. 问题定义 假设我们有两个点云集合 ...

  6. mp4文件格式解析二

    目前MP4的概念被炒得很火,也很乱.最开始MP4指的是音频(MP3的升级版),即MPEG-2 AAC标准.随后MP4概念被转移到视频上,对应的是MPEG-4标准.而现在我们流行的叫法,多半是指能播放M ...

  7. 软工Alpha七天冲刺

    七天冲刺博客: 1.第一篇Scrum冲刺博客 2.第二篇Scrum冲刺博客 3.第三篇Scrum冲刺博客 4.第四篇Scrum冲刺博客 5.第五篇Scrum冲刺博客 6.第六篇Scrum冲刺博客 7. ...

  8. Spring Cloud Eureka的自我保护模式与实例下线剔除

    之前我说明了Eureka注册中心的保护模式,由于在该模式下不能剔除失效节点,故按原有配置在实际中不剔除总感觉不是太好,所以深入研究了一下.当然,这里重申一下,不管实例是否有效剔除,消费端实现Ribbo ...

  9. odoo10学习笔记六:工作流、安全机制、向导

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/11189289.html 一:工作流 工作流是与业务流程相关联的模型,可用于跟踪工序的动态演变过程. 工作流. ...

  10. [TCP/IP] TCP的报文头

    1.源端口和目的端口:各占2个字节,分别写入源端口和目的端口: 2.序列号:占4个字节,TCP连接中传送的字节流中的每个字节都按顺序编号.例如,一段报文的序号字段值是 301 ,而携带的数据共有100 ...