哈希算法题目:设计一个基于哈希的分布式实时排行榜系统(支持分数更新和Top K查询)
字数 1272 2025-11-04 11:59:17

哈希算法题目:设计一个基于哈希的分布式实时排行榜系统(支持分数更新和Top K查询)

题目描述:设计一个分布式实时排行榜系统,支持以下操作:

  1. addScore(playerId, score) - 为玩家添加分数(可正可负)
  2. top(k) - 返回前k名最高分的玩家ID
  3. reset(playerId) - 重置玩家的分数为0

系统需要支持高并发访问,并且要保证在大数据量下的查询效率。

解题过程

第一步:分析需求和数据特点

  • 玩家数量可能达到百万级别
  • 分数会频繁更新,需要支持高并发写入
  • Top K查询需要快速响应
  • 需要支持分布式部署

第二步:设计基本数据结构
我们需要两个核心数据结构:

  1. 哈希表:存储玩家ID到当前分数的映射

    • 键:playerId(字符串或整数)
    • 值:当前分数(整数)
    • 作用:支持O(1)时间查询和更新单个玩家的分数
  2. 有序集合:按分数排序的玩家集合

    • 使用跳表(Skip List)或平衡树实现
    • 支持按分数范围快速查询
    • 支持O(log n)时间的插入、删除和更新

第三步:详细设计操作流程

addScore操作

  1. 在哈希表中查找玩家当前分数
  2. 如果玩家不存在,初始化分数为0
  3. 计算新分数 = 旧分数 + 输入分数
  4. 从有序集合中删除旧的分数记录(如果存在)
  5. 将新分数插入有序集合
  6. 更新哈希表中的分数值

示例代码逻辑:

def addScore(playerId, score):
    # 1. 从哈希表获取当前分数
    old_score = hash_map.get(playerId, 0)
    
    # 2. 计算新分数
    new_score = old_score + score
    
    # 3. 如果之前有分数,从有序集合删除旧记录
    if old_score != 0:
        sorted_set.remove((old_score, playerId))
    
    # 4. 插入新记录到有序集合
    sorted_set.add((new_score, playerId))
    
    # 5. 更新哈希表
    hash_map[playerId] = new_score

top(k)操作

  1. 从有序集合的尾部(分数最高端)开始遍历
  2. 取前k个元素
  3. 返回对应的玩家ID列表
def top(k):
    results = []
    # 从分数最高端开始遍历(降序排列)
    for i in range(min(k, len(sorted_set))):
        # 获取第i高的分数和玩家ID
        score, playerId = sorted_set[-1-i]
        results.append(playerId)
    return results

reset操作

def reset(playerId):
    if playerId in hash_map:
        old_score = hash_map[playerId]
        # 从有序集合中删除
        sorted_set.remove((old_score, playerId))
        # 从哈希表中删除或设为0
        hash_map[playerId] = 0
        # 插入0分记录(如果需要显示在排行榜中)
        sorted_set.add((0, playerId))

第四步:处理分布式场景

在分布式环境中,我们需要考虑数据分片:

数据分片策略

  1. 按玩家ID分片:将玩家哈希到不同的服务器节点

    • 优点:单个玩家的操作都在同一节点完成
    • 挑战:Top K查询需要合并所有节点的数据
  2. 全局有序集合的维护

    • 每个节点维护自己分片内的局部排行榜
    • 定期合并局部排行榜生成全局排行榜
    • 使用缓存机制存储最近的Top K结果

分布式Top K查询优化

  1. 阈值算法(TA算法)

    • 并行查询所有分片,按分数降序获取记录
    • 维护一个最小堆来合并结果
    • 当已经收集到k个分数不低于其他分片当前最高分的记录时停止
  2. 缓存策略

    • 缓存最近的Top K查询结果
    • 设置合适的缓存过期时间
    • 当分数更新时,使受影响的缓存失效

第五步:处理并发和一致性

并发控制

  1. 使用细粒度锁:对每个玩家ID使用独立的锁
  2. 乐观锁:使用版本号或CAS操作
  3. 读写分离:读操作访问副本,写操作访问主节点

一致性保证

  1. 最终一致性:允许短暂的数据不一致
  2. 使用事务保证哈希表和有序集合的原子更新
  3. 写入日志进行故障恢复

第六步:性能优化

内存优化

  1. 使用压缩数据结构存储分数
  2. 对玩家ID使用字符串驻留(string interning)
  3. 定期清理分数为0的不活跃玩家

查询优化

  1. 使用布隆过滤器快速判断玩家是否存在
  2. 对频繁查询的Top K结果进行预计算
  3. 使用多级缓存减少数据库访问

这个设计结合了哈希表的快速查找和有序集合的高效排序,通过分布式架构支持水平扩展,能够满足大规模实时排行榜的需求。

哈希算法题目:设计一个基于哈希的分布式实时排行榜系统(支持分数更新和Top K查询) 题目描述 :设计一个分布式实时排行榜系统,支持以下操作: addScore(playerId, score) - 为玩家添加分数(可正可负) top(k) - 返回前k名最高分的玩家ID reset(playerId) - 重置玩家的分数为0 系统需要支持高并发访问,并且要保证在大数据量下的查询效率。 解题过程 : 第一步:分析需求和数据特点 玩家数量可能达到百万级别 分数会频繁更新,需要支持高并发写入 Top K查询需要快速响应 需要支持分布式部署 第二步:设计基本数据结构 我们需要两个核心数据结构: 哈希表 :存储玩家ID到当前分数的映射 键:playerId(字符串或整数) 值:当前分数(整数) 作用:支持O(1)时间查询和更新单个玩家的分数 有序集合 :按分数排序的玩家集合 使用跳表(Skip List)或平衡树实现 支持按分数范围快速查询 支持O(log n)时间的插入、删除和更新 第三步:详细设计操作流程 addScore操作 : 在哈希表中查找玩家当前分数 如果玩家不存在,初始化分数为0 计算新分数 = 旧分数 + 输入分数 从有序集合中删除旧的分数记录(如果存在) 将新分数插入有序集合 更新哈希表中的分数值 示例代码逻辑: top(k)操作 : 从有序集合的尾部(分数最高端)开始遍历 取前k个元素 返回对应的玩家ID列表 reset操作 : 第四步:处理分布式场景 在分布式环境中,我们需要考虑数据分片: 数据分片策略 : 按玩家ID分片 :将玩家哈希到不同的服务器节点 优点:单个玩家的操作都在同一节点完成 挑战:Top K查询需要合并所有节点的数据 全局有序集合的维护 : 每个节点维护自己分片内的局部排行榜 定期合并局部排行榜生成全局排行榜 使用缓存机制存储最近的Top K结果 分布式Top K查询优化 : 阈值算法(TA算法) : 并行查询所有分片,按分数降序获取记录 维护一个最小堆来合并结果 当已经收集到k个分数不低于其他分片当前最高分的记录时停止 缓存策略 : 缓存最近的Top K查询结果 设置合适的缓存过期时间 当分数更新时,使受影响的缓存失效 第五步:处理并发和一致性 并发控制 : 使用细粒度锁:对每个玩家ID使用独立的锁 乐观锁:使用版本号或CAS操作 读写分离:读操作访问副本,写操作访问主节点 一致性保证 : 最终一致性:允许短暂的数据不一致 使用事务保证哈希表和有序集合的原子更新 写入日志进行故障恢复 第六步:性能优化 内存优化 : 使用压缩数据结构存储分数 对玩家ID使用字符串驻留(string interning) 定期清理分数为0的不活跃玩家 查询优化 : 使用布隆过滤器快速判断玩家是否存在 对频繁查询的Top K结果进行预计算 使用多级缓存减少数据库访问 这个设计结合了哈希表的快速查找和有序集合的高效排序,通过分布式架构支持水平扩展,能够满足大规模实时排行榜的需求。