[LeetCode] Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复
Design a data structure that supports all following operations in average O(1) time.
Note: Duplicate elements are allowed.
insert(val): Inserts an item val to the collection.remove(val): Removes an item val from the collection if present.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
类似题目:
参考资料:
https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复的更多相关文章
- [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 ...
- [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 ...
- Leetcode: Insert Delete GetRandom O(1) - Duplicates allowed
Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...
- 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). ...
- 381. Insert Delete GetRandom O(1) - Duplicates allowed
Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...
- [LeetCode] Insert Delete GetRandom O(1) 常数时间内插入删除和获得随机数
Design a data structure that supports all following operations in average O(1) time. insert(val): In ...
- [LeetCode] 380. Insert Delete GetRandom O(1) 常数时间内插入删除和获得随机数
Design a data structure that supports all following operations in average O(1) time. insert(val): In ...
- [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 ...
- LeetCode 381. Insert Delete GetRandom O(1) - Duplicates allowed
原题链接在这里:https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/?tab=Description ...
随机推荐
- PHPStorm配置自己喜欢的主题
PHPstorm默认的主题和可选的主题有时候不能满足有些人的需求,怎么配置自己喜欢的主题呢? 1.首先先去下载自己喜欢的主题:http://www.phpstorm-themes.com/ 但是在下载 ...
- EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针
一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...
- php函数强大的 strtotime
使用strtotime可以将各种格式的时间字符串转换为时间戳 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 转换常规时间格式 echo date('Y-m-d H:i: ...
- PHP 单例模式
一.什么是单例模式? 1.含义 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例.它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用. 2. ...
- SSM三大框架整合详细教程(Spring+SpringMVC+MyBatis)【转】
使用SSM(Spring.SpringMVC和Mybatis)已经有三个多月了,项目在技术上已经没有什么难点了,基于现有的技术就可以实现想要的功能,当然肯定有很多可以改进的地方.之前没有记录SSM整合 ...
- push方法的兼容性问题
在IE8及以下中,不支持aplly方法中的第二个参数是 伪数组 需要对push方法进行封装. 将 push 的判断,放入一个沙箱中: 好处:在页面加载的时候就会执行这段代码,保证了代码只会检测一次 以 ...
- arcgis 按面积分割, 按比例分割面积,按等份批量面积分割工具
arcgis 按面积分割, 按比例分割面积,按等份批量面积分割工具 视频下载:https://yunpan.cn/cvujkpKIqwccn 访问密码 e9f4
- swift 学习笔记
1. 数组中取出字符串的方法: 1)let string = "\arr[0]" 2) let string = String(stringInterpolationSegment ...
- iOS学习15之OC集合
1.数组类 1> 回顾C语言数组 数组是一个有序的集合, 来存储相同数据类型的元素. 通过下标访问数组中的元素,下标从 0 开始. 2> 数组 数组是一个有序的集合,OC中的数组只能存储对 ...
- SegmentControl 那些令人烦恼的事儿
每个人的曾经都很苦逼.我知道我很卑微,但我不曾放慢脚步,在这条路上至死不悔.愿与你同行. UISegmentControl 概述 UISegmentControl 是系统的段选择控件,具有简洁大方的外 ...