Skip to main content

380.380. 插入 删除 和随机获取 O(1)

标签: hash-table, design

难度: Medium

通过率: 54.78%

原题链接: https://leetcode.com/problems/insert-delete-getrandom-o1/description/

题目描述

实现 RandomizedSet 类: RandomizedSet() 初始化 RandomizedSet 对象。 bool insert(int val) 如果 set 中不存在 val,插入并返回 true,否则返回 false。 bool remove(int val) 如果 set 中存在 val,移除并返回 true,否则返回 false。 int getRandom() 返回随机的元素(保证至少有一个元素存在)。所有元素被返回的概率相等。 所有方法都应该在平均 O(1) 时间复杂度内完成。

解题思路

为了实现 O(1)O(1) 时间复杂度地插入、删除和获取随机元素,我们可以使用一个数组和一个哈希表:

  1. 插入操作

    • 首先检查元素是否在集合中存在。
    • 如果存在,返回 false
    • 如果不存在,将元素加入数组,并在哈希表中记录该元素的索引。
    • 返回 true
  2. 删除操作

    • 检查元素是否在集合中存在。
    • 如果不存在,返回 false
    • 如果存在,将该元素在数组中的位置与最后一个元素进行交换。
    • 更新最后一个元素在哈希表的索引。
    • 移除数组的最后一个元素,并在哈希表中删除该元素。
    • 返回 true
  3. 随机获取操作

    • 随机选取数组中的一个元素,因为数组大小是动态管理的,所有元素在数组中的概率是相等的。

通过这种方法,插入和删除操作都能在平均 O(1)O(1) 时间内完成,因为我们只需操作数组尾部的元素;而随机获取操作能在 O(1)O(1) 时间内实现,因为只需从数组直接随机访问。

代码实现

import random

class RandomizedSet:
def __init__(self):
# 存储元素形成的列表
self.nums = []
# 存储每个元素的索引
self.num_to_index = {}

def insert(self, val: int) -> bool:
if val in self.num_to_index:
return False
# 将元素加入数组末尾
self.num_to_index[val] = len(self.nums)
self.nums.append(val)
return True

def remove(self, val: int) -> bool:
if val not in self.num_to_index:
return False
# 获取要删除元素的索引
index = self.num_to_index[val]
# 用数组的最后一个元素覆盖要删除的元素
last_val = self.nums[-1]
self.nums[index] = last_val
self.num_to_index[last_val] = index
# 移除最后一个元素
self.nums.pop()
del self.num_to_index[val]
return True

def getRandom(self) -> int:
# 从数组选择随机元素
return random.choice(self.nums)

复杂度分析

时间复杂度: 每次插入、删除操作都需要进行常数时间内的数组操作和哈希表操作,所以期望时间复杂度是 O(1)O(1)。随机获取操作使用标准库提供的随机选择器,也是 O(1)O(1)

空间复杂度: 需要开辟额外的空间存储哈希表和数组,所以空间复杂度为 O(n)O(n),其中 nn 是元素的数量。