题目
题目来源:力扣(LeetCode)
设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构。
insert(val):当元素 val 不存在时,向集合中插入该项。
remove(val):元素 val 存在时,从集合中移除该项。
getRandom:随机返回现有集合中的一项。每个元素应该有相同的概率被返回。
示例 :
// 初始化一个空的集合。RandomizedSet randomSet = new RandomizedSet();// 向集合中插入 1 。返回 true 表示 1 被成功地插入。randomSet.insert(1);// 返回 false ,表示集合中不存在 2 。randomSet.remove(2);// 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。randomSet.insert(2);// getRandom 应随机返回 1 或 2 。randomSet.getRandom();// 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。randomSet.remove(1);// 2 已在集合中,所以返回 false 。randomSet.insert(2);// 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。randomSet.getRandom();
思路分析
数组 + 哈希表
数组存储值,在 gerRandom 时可以获得真正的随机值,哈希表存储值到索引的映射关系,可以在常数时间内获取到要删除元素的索引。
因此,我们使用以下的数据结构:
- 动态数组存储元素值
- 哈希表存储值到索引的映射
var RandomizedSet = function() {// 存储值和索引的对应关系this.map= new Map();// 存储值this.list = [];};
insert 操作时
若元素不存在:
- 将元素添加到动态数组
- 在哈希表中添加值到索引的映射
- 最后返回 true
若元素已存在:
返回false
RandomizedSet.prototype.insert = function(val) {if (!this.map.has(val)) return false;this.list.push(val);this.map.set(val, this.list.length - 1);return true;};
remove 操作时
若元素不存在:
- 返回false
若元素存在:
- 在哈希表中查找要删除元素的索引
- 将要删除元素与最后一个元素交换
- 删除最后一个元素
- 更新哈希表中的对应关系
- 最后返回 true ```javascript RandomizedSet.prototype.remove = function(val) { if (!this.map.has(val)) return false; // 在哈希表中查找要删除元素的索引 const index = this.map.get(val); const len = this.list.length - 1; // 将要删除元素与最后一个元素交换 [this.list[index], this.list[len]] = [this.list[len], this.list[index]]; // 更新哈希表中的对应关系 this.map.set(rhis.list[index], index); // 删除列表中的最后一个元素 this.list.pop(); // 删除哈希表中当前已删除元素的对应关系 this.map.delete(val); return true;
};
**getRandom 操作时**借助 Math.random * list.length 与 0 做位运算,获取随机索引```javascriptRandomizedSet.prototype.getRandom = function() {// | 位运算符 OR, 一对数位执行位运算 OR 时,如果其中一位是 1 则返回 1// 0 | 0 结果为 0// 0 | 1 结果为 1// 1 | 0 结果为 1// 1 | 1 结果为 1// Math.random() * this.list.length | 0 获取随机索引return this.list[Math.random() * this.list.length | 0];};
完整代码
/*** Initialize your data structure here.*/var RandomizedSet = function() {// 存储值和索引的对应关系this.map= new Map();// 存储值this.list = [];};/*** Inserts a value to the set. Returns true if the set did not already contain the specified element.* @param {number} val* @return {boolean}*/RandomizedSet.prototype.insert = function(val) {// 元素已在集合中,返回 falseif (this.map.has(val)) return false;// 向集合中插入元素,并返回 truethis.list.push(val);this.map.set(val, this.list.length - 1);return true;};/*** Removes a value from the set. Returns true if the set contained the specified element.* @param {number} val* @return {boolean}*/RandomizedSet.prototype.remove = function(val) {// 当前要删除的元素不在集合中,返回 falseif (!this.map.has(val)) return false;// 在哈希表中查找要删除元素的索引const index = this.map.get(val);const len = this.list.length - 1;// 将要删除元素与最后一个元素交换[this.list[index], this.list[len]] = [this.list[len], this.list[index]];// 更新哈希表中的对应关系this.map.set(this.list[index], index);// 删除列表中的最后一个元素this.list.pop();// 删除哈希表中当前已删除元素的对应关系this.map.delete(val);return true;};/*** Get a random element from the set.* @return {number}*/RandomizedSet.prototype.getRandom = function() {// | 位运算符 OR, 一对数位执行位运算 OR 时,如果其中一位是 1 则返回 1// 0 | 0 结果为 0// 0 | 1 结果为 1// 1 | 0 结果为 1// 1 | 1 结果为 1// Math.random() * this.list.length | 0 获取随机索引return this.list[Math.random() * this.list.length | 0];};/*** Your RandomizedSet object will be instantiated and called as such:* var obj = new RandomizedSet()* var param_1 = obj.insert(val)* var param_2 = obj.remove(val)* var param_3 = obj.getRandom()*/
