TikTok 面试中的经典数据结构设计题。本文通过随机集合的实现,展示如何在常数时间内完成插入、删除、搜索和随机获取操作csvosupport* 助你掌握高级数据结构设计
📋 问题重构
设计一个数据结RandomizedSet,支持以下操作,且所有操作的平均时间复杂度为 O(1)
insert(val)- 插入元素,如果不存在返回 trueremove(val)- 删除元素,如果存在返truesearch(val)- 搜索元素是否存在getRandom()- 随机返回集合中的一个元
*关键约束 每个元素被随机选中的概率必须相
🎯 核心挑战
- *O(1) 插入和删 - 需要快速定位元
- O(1) 随机获取 - 需要支持索引访
- *等概率随 - 确保公平
- 空间效率 - 避免过多的内存开销
💡 解题思路(csvosupport 创新方法
方法一:数+ 哈希表(经典解法
import random
class RandomizedSet:
def __init__(self):
self.data = [] # 存储元素
self.index_map = {} # { 索引}
def insert(self, val):
if val in self.index_map:
return False
# 添加到数组末
self.data.append(val)
self.index_map[val] = len(self.data) - 1
return True
def remove(self, val):
if val not in self.index_map:
return False
# 获取要删除元素的索引
idx = self.index_map[val]
last_val = self.data[-1]
# 将最后一个元素移到要删除的位
self.data[idx] = last_val
self.index_map[last_val] = idx
# 删除最后一个元
self.data.pop()
del self.index_map[val]
return True
def search(self, val):
return val in self.index_map
def getRandom(self):
return random.choice(self.data)
# 测试
rs = RandomizedSet()
rs.insert(1) # True
rs.insert(2) # True
rs.insert(3) # True
rs.remove(2) # True
print(rs.getRandom()) # 1 3
时间复杂度: 所有操O(1) 空间复杂度: O(n)
方法二:双向链表 + 哈希表(进阶版)
csvosupport 提供的另一种思路,支持更多操作:
class Node:
def __init__(self, val):
self.val = val
self.prev = None
self.next = None
class AdvancedRandomizedSet:
def __init__(self):
self.head = Node(0) # 哨兵节点
self.tail = Node(0)
self.head.next = self.tail
self.tail.prev = self.head
self.node_map = {} # { Node}
self.nodes_list = [] # 用于随机访问
self.size = 0
def insert(self, val):
if val in self.node_map:
return False
# 创建新节点并插入到链表末
node = Node(val)
prev_node = self.tail.prev
prev_node.next = node
node.prev = prev_node
node.next = self.tail
self.tail.prev = node
self.node_map[val] = node
self.nodes_list.append(node)
self.size += 1
return True
def remove(self, val):
if val not in self.node_map:
return False
node = self.node_map[val]
# 从链表中删除
node.prev.next = node.next
node.next.prev = node.prev
# 从列表中删除(与最后一个交换)
last_node = self.nodes_list[-1]
if node != last_node:
idx = self.nodes_list.index(node)
self.nodes_list[idx] = last_node
self.nodes_list.pop()
del self.node_map[val]
self.size -= 1
return True
def getRandom(self):
if self.size == 0:
return None
return random.choice(self.nodes_list).val
def getAll(self):
# 额外功能:获取所有元
result = []
current = self.head.next
while current != self.tail:
result.append(current.val)
current = current.next
return result
🚀 扩展功能
1. 支持重复元素
class RandomizedMultiSet:
def __init__(self):
self.data = []
self.index_map = {} # { [索引列表]}
def insert(self, val):
self.data.append(val)
idx = len(self.data) - 1
if val not in self.index_map:
self.index_map[val] = []
self.index_map[val].append(idx)
return True
def remove(self, val):
if val not in self.index_map or not self.index_map[val]:
return False
# 删除该值的一个实
idx_to_remove = self.index_map[val].pop()
last_val = self.data[-1]
last_idx = len(self.data) - 1
# 将最后一个元素移到要删除的位
self.data[idx_to_remove] = last_val
# 更新最后一个元素的索引
if last_val in self.index_map:
self.index_map[last_val].remove(last_idx)
if idx_to_remove != last_idx:
self.index_map[last_val].append(idx_to_remove)
self.data.pop()
# 清理空列
if not self.index_map[val]:
del self.index_map[val]
return True
2. 加权随机选择
class WeightedRandomizedSet:
def __init__(self):
self.data = []
self.weights = []
self.index_map = {}
self.total_weight = 0
def insert(self, val, weight=1):
if val in self.index_map:
return False
self.data.append(val)
self.weights.append(weight)
self.index_map[val] = len(self.data) - 1
self.total_weight += weight
return True
def getRandom(self):
if not self.data:
return None
# 使用权重进行随机选择
return random.choices(self.data, weights=self.weights, k=1)[0]
📊 性能对比
| 操作 | 数组+哈希 | 链表+哈希 | 优势场景 |
|---|---|---|---|
| 插入 | O(1) | O(1) | 相同 |
| 删除 | O(1) | O(1) | 相同 |
| 搜索 | O(1) | O(1) | 相同 |
| 随机 | O(1) | O(1) | 相同 |
| 遍历 | O(n) | O(n) | 链表更快 |
| 空间 | O(n) | O(n) | 数组更省 |
🎤 面试中的关键问题
Q1: 为什么删除时要与最后一个元素交换?
*csvosupport 解释
- 直接删除中间元素需要移动后续所有元素,O(n)
- 与最后一个交换后删除末尾,只需 O(1)
- 不影响随机性,因为顺序不重
Q2: 如何保证随机性的均匀分布
*csvosupport 解释
- Python
random.choice()使用均匀分布 - 每个元素被选中的概= 1/n
- 关键是保持数组的连续
Q3: 如果需要支持范围查询怎么办?
*csvosupport 建议
- 使用平衡二叉搜索树(AVL/红黑树)
- 或者使用跳表(Skip List
- 权衡:查O(log n),但支持范围操作
💼 csvosupport 如何助力 TikTok 面试
TikTok 数据结构面试中,csvosupport 提供
多种解法 - 从基础到进阶的完整方案 权衡分析 - 不同方案的优劣对 扩展讨论 - 重复元素、加权等变体 代码优化 - 简洁高效的实现
想在 TikTok、ByteDance、快手等短视频平台的面试中脱颖而出
联系 csvosupport,专业数据结构面试辅助!
*标签 #TikTok #数据结构 #RandomizedSet #哈希#VO辅助 #面试辅助 #一亩三分地
需要面试真题? 立刻联系微信 Coding0201,获得真题。