一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
力扣380. O(1) 时间插入、删除和获取随机元素
一、题目描述:
实现RandomizedSet 类:
RandomizedSet() 初始化 RandomizedSet 对象
bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。
bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false 。
int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。
你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1) 。
示例:
输入 ["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
输出
[null, true, false, true, 2, true, false, 2]
解释 RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
randomizedSet.remove(2); // 返回 false ,表示集合中不存在 2 。
randomizedSet.insert(2); // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
randomizedSet.getRandom(); // getRandom 应随机返回 1 或 2 。
randomizedSet.remove(1); // 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
randomizedSet.insert(2); // 2 已在集合中,所以返回 false 。
randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。
提示:
-2^31 <= val <= 2^31 - 1
最多调用 insert、remove 和 getRandom 函数 2 * 10^5 次
在调用 getRandom 方法时,数据结构中 至少存在一个 元素。
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/in… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、思路分析:
-
这道题考察了什么思想?你的思路是什么?
O(1)的时间复杂度,这让我想起了哈希表,初始化一个list,名为nums,另外为了记录各数的索引,避免删除时遍历nums,我们建立一个索引字典index_map。插入时,判断值是否是index_map的键,如果不是,就append到nums中,另外添加索引,返回True。如果是,就返回False。
移除时,判断该值是否是字典的键,如果不是就返回False,如果是,因为要保证时间复杂度为1,所以我们将最后一个元素val覆盖到要删除的值的位置,并更新最后一个元素val的索引。
随机获取值时,我们利用choice函数, choice() 方法返回一个列表,元组或字符串的随机项。
-
做题的时候是不是一次通过的,遇到了什么问题,需要注意什么细节?
不是,在insert的时候,我先append元素val,然后再添加索引,但是我的索引是nums的长度,所以有两种解决办法:
self.nums.append(val) self.index_map[val] = len(self.nums)-1self.index_map[val] = len(self.nums self.nums.append(val)这样就能通过啦~
-
有几种解法,哪种解法时间复杂度最低,哪种解法空间复杂度最低,最优解法是什么?其他人的题解是什么,谁的效率更好一些?用不同语言实现的话,哪个语言速度最快?
我们能够看到我这样的解法执行用时和内存消耗均不太好,所以看看大佬们是怎样解决这个问题的吧~
```
class RandomizedSet:
def __init__(self):
self.nums = []
self.pos = {}
def insert(self, val):
if val not in self.pos:
self.nums.append(val)
self.pos[val] = len(self.nums) - 1
return True
return False
def remove(self, val):
if val in self.pos:
idx, last = self.pos[val], self.nums[-1]
self.nums[idx], self.pos[last] = last, idx
self.nums.pop(-1)
del self.pos[val]
return True
return False
def getRandom(self):
return random.choice(self.nums)
# Your RandomizedSet object will be instantiated and called as such:
# obj = RandomizedSet()
# param_1 = obj.insert(val)
# param_2 = obj.remove(val)
# param_3 = obj.getRandom()
作者:Jam007
链接:https://leetcode-cn.com/problems/insert-delete-getrandom-o1/solution/by-jam007-r8xf/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
```
三、AC 代码:
class RandomizedSet:
def __init__(self):
self.nums = []
self.index_map = {}
def insert(self, val: int) -> bool:
if val in self.index_map:
return False
self.index_map[val] = len(self.nums)
self.nums.append(val)
return True
def remove(self, val: int) -> bool:
if val not in self.index_map:
return False
index = self.index_map[val]
self.nums[index] = self.nums[-1]
self.index_map[self.nums[-1]] = index
self.nums.pop()
del self.index_map[val]
return True
def getRandom(self) -> int:
return choice(self.nums)
# Your RandomizedSet object will be instantiated and called as such:
# obj = RandomizedSet()
# param_1 = obj.insert(val)
# param_2 = obj.remove(val)
# param_3 = obj.getRandom()
四、总结:
做这类题目,每一步都需要注意,步骤的先后均会导致不同的结果。