携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
每日刷题 2022.08.03
- leetcode原题链接:leetcode.cn/problems/Fo…
- 难度:简单
- 方法:map+数组
题目
- 设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构:
- insert(val):当元素 val 不存在时返回 true ,并向集合中插入该项,否则返回 false 。
- remove(val):当元素 val 存在时返回 true ,并从集合中移除该项,否则返回 false 。
- getRandom:随机返回现有集合中的一项。每个元素应该有 相同的概率 被返回。
示例
输入: inputs = ["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
输出: [null, true, false, true, 2, true, false, 2]
解释:
RandomizedSet randomSet = new RandomizedSet(); // 初始化一个空的集合
randomSet.insert(1); // 向集合中插入 1 , 返回 true 表示 1 被成功地插入
randomSet.remove(2); // 返回 false,表示集合中不存在 2
randomSet.insert(2); // 向集合中插入 2 返回 true ,集合现在包含 [1,2]
randomSet.getRandom(); // getRandom 应随机返回 1 或 2
randomSet.remove(1); // 从集合中移除 1 返回 true 。集合现在包含 [2]
randomSet.insert(2); // 2 已在集合中,所以返回 false
randomSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom 总是返回 2
解题思路
- 分析题目含义:需要在时间复杂度O(1)的情况下实现:插入、删除、随机获取集合中的一项,这三种操作。
- 首先想到的是使用
map集合,但是好像map集合没有办法在o(1)时间内获取集合中的一项,因此放弃了使用map集合。后续想到示例中所给的数据在集合中都只能出现一次,那么可以使用set集合来进行存储,最后随机获取的时候,可以将set集合转换成数组,再通过随机数组的下标来获取元素值。 - 使用
set的做法可行,但是时间复杂度较高。思考可能是因为将集合set转换成数组,每次都需要将数组全部遍历一遍,这样的话时间复杂度就不再是o(1)而是o(n)
巧妙的解法
- 使用
map集合 +数组,最开始也想到了使用map,但是止步于随机获取集合中的一项这个条件,的确单靠map集合是无法实现的,因此后面考虑到了结合数组arr来实现. - 使用
map集合key记录当前的值,value记录当前值在数组中所对应的下标idx。 - 重点:如何处理随机的呢?如果要删除一个元素
del,那么就将当前arr数组中最后一个元素换到del的位置上,删除掉原本的del的信息即可。下次再随机数组长度内的下标就可以o(1)的时间复杂度获取到元素 - 始终维护
arr数组的长度,删除arr中的一个元素,就将arr尾部的元素和其替换。需要注意,如果当前需要删除的元素就是arr数组尾部的元素,那么就不需要修改信息,直接将其删除就可以了。
AC代码
/**
* Initialize your data structure here.
*/
var RandomizedSet = function() {
// 新的做法,使用map和数组结合
// map集合中记录当前的值和下标
this.map = new Map();
// 存放值
this.arr = [];
this.idx = -1;
};
/**
* 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) {
// console.log('insert::', this.map)
if(this.map.has(val)) return false;
this.idx++;
this.arr[this.idx] = val;
this.map.set(val, this.idx);
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) {
if(!this.map.has(val)) return false;
// 存在的时候
// 删除
const col = this.map.get(val);
if(col === this.idx) {
// 当前的就是最后一个元素
this.arr.pop();
this.map.delete(val);
} else {
this.map.delete(val);
const cur = this.arr[this.idx];
this.arr[col] = cur;
this.map.set(cur, col);
}
this.idx--;
return true;
};
/**
* Get a random element from the set.
* @return {number}
*/
RandomizedSet.prototype.getRandom = function() {
// const n = this.arr.length;
// console.log(this.arr)
const r = Math.floor(Math.random() * (this.idx + 1));
return this.arr[r];
};