字节交易后端一面:流式 Top K 与懒加载单例
- 轮次
- 一面
- 时间
- 2026-08
- 来源
- 牛客网
《面试题目》
- 能否做一下自我介绍,并介绍实习中负责的工作?
- 项目里的提示词是怎样设计出来的?
- 项目的整体架构是什么样的?
- 怎样把非结构化需求文档拆成结构化的图片任务?
- 在什么背景下引入冷热分离,主要解决什么问题?
- 从输入 URL 到页面显示,完整过程是什么?网络层使用什么协议?
- 如何从海量数据中寻找 Top K?
- 数据持续到达时,怎样设计一个维护状态的 Top K 接口?
- Java ConcurrentHashMap 的实现原理是什么?
- 如何实现单例模式,并做到延迟初始化和线程安全?
- 如何求字符串中最长的无重复字符子串?
- 目前是否在北京实习,能否到北京实习?
- 对未来的工作有什么计划?
- 有哪些问题想向面试官了解?
《参考解析》
Top K 先确认排的是数值还是频次
若要找最大的 K 个数,可以维护大小为 K 的最小堆:新值超过堆顶才替换,每次更新花费 O(log K),空间为 O(K)。返回有序结果时还需要排序,堆本身不是有序列表。
若要找出现最频繁的 K 个元素,只有一个小堆不够,还要记录频次。无限数据流中,精确计数所需空间会随不同元素数量增长;若允许近似结果,才考虑有误差界限的摘要算法。接口设计还要明确是否按时间窗口统计,以及重启后状态怎么恢复。
并发容器不自动包办复合操作
ConcurrentHashMap 支持并发读写,但先 get 再计算再 put 是多个步骤,可能覆盖其他线程的更新。单个键的原子更新可用 compute、merge 或 putIfAbsent;跨键业务约束需要另行设计。迭代时也不能把读到的整张表视为某一时刻的原子快照。参见 ConcurrentHashMap 官方文档。
懒加载可以借助类初始化
静态内部类持有实例,外部 getInstance() 访问该类时才触发初始化,由类初始化机制提供同步。若使用双重检查锁,则实例引用应声明为 volatile,并在同步块内再次检查。两种写法都要先明确讨论范围,例如是否需要处理反射、序列化和多个类加载器。
最长无重复子串维护左边界
用表记录每个字符上次出现的位置。右指针扫描字符时,把左边界更新为 max(原左边界, 上次位置 + 1),再更新最大窗口长度。这里的 max 不能漏,否则遇到窗口外的重复字符会把左边界往回移。