LLD 和 OOD 编码面试怎么准备:从购物车、权限系统到告警引擎
LLD 和 OOD 编码面试怎么准备:从购物车、权限系统到告警引擎
很多工程师刷了大量算法题,却在 LLD 或 OOD 编码面试里表现不稳定。原因是这类面试不只考“能不能写出函数”,还考你能不能把一个小系统拆成合理的数据模型、API、状态转移和测试用例。
近年的面试里,小型系统实现题很常见:购物车折扣、文件系统、资源权限、告警执行引擎、棋类游戏、日志统计、任务调度器的简化版本。它们看起来不像传统 LeetCode,但底层考察点很集中。
先识别题目的核心状态
LLD 面试的第一步不是写 class,而是找状态。
例如购物车系统里,核心状态可能是:
- 当前 cart 里有哪些 recipe
- 每种 ingredient 当前数量
- 每种 ingredient 对应的 discount tier
- 当前总折扣
- undo stack 和 redo stack
资源权限系统里,核心状态可能是:
- user 到 role 的映射
- role 到 permission 的映射
- resource 的层级关系
- permission 是否继承
- deny 和 allow 的优先级
告警引擎里,核心状态可能是:
- alert 配置
- 每个 alert 上次执行时间
- 当前状态是 PASS 还是 CRITICAL
- 上次通知时间
- repeat interval
面试官希望看到你能把业务描述转成可维护状态,而不是把所有逻辑塞进一个函数。
API 设计要主动说明语义
小系统题通常会给几个 API,比如 add、remove、get_total、undo、redo。你需要主动确认:
- 重复添加是 no-op 还是报错?
- 删除不存在对象时怎么处理?
- 返回值要不要表示操作是否成功?
- undo 一个 no-op 操作是否应该入栈?
- redo 在新操作后是否清空?
- 查询接口是否必须 O(1)?
这些问题会直接影响实现。
例如 undo/redo 题里,只有真正改变状态的操作才应该进入 undo stack。否则用户连续 undo 时会遇到“撤销了一个其实没发生过的操作”,行为会很奇怪。
复杂度优化要围绕增量更新
很多 LLD 面试的 follow-up 都会问性能。
购物车折扣可以每次 get_total_discount 时重新扫描所有 ingredient,但如果查询频繁,就应该在 add/remove 时增量维护 total_discount。
日志统计可以每次查询时排序算 median,但如果数据量大,要考虑每个 endpoint 维护 response time 列表,或者在 streaming 场景里用两个 heap 维护中位数。
权限继承可以每次查询时沿 resource tree 向上找,也可以缓存有效权限,但缓存会带来更新失效问题。
你不一定要一开始写最复杂版本,但要能说明:
先实现正确版本
瓶颈在哪里
如果读多写少怎么优化
如果写多读少怎么优化
缓存失效如何处理
这就是面试官要的工程判断。
状态机比 if-else 更稳
告警引擎、订单、任务调度、游戏状态这类题,最好显式讲状态机。
例如告警可以有:
PASS → CRITICAL:首次通知
CRITICAL → CRITICAL:根据 repeat interval 决定是否重复通知
CRITICAL → PASS:发送 resolve
PASS → PASS:不动作
这样写比一堆 if-else 更清楚,也更容易覆盖测试。
棋类或游戏题也是类似。不要只检查“有没有赢”,还要考虑:
- 当前轮到谁
- 落子是否合法
- 游戏是否已经结束
- 是否平局
- 输出格式是否稳定
- AI 或 random player 是否可能无限循环
很多候选人不是不会算法,而是忘了业务状态的终止条件。
测试用例要覆盖边界,不只是 happy path
LLD 面试里,自己写测试很重要。建议固定准备这几类:
- 空输入
- 重复操作
- 删除不存在对象
- 边界阈值
- 状态来回切换
- tie-breaking
- 深层嵌套
- undo/redo 连续调用
- 新操作清空 redo
以购物车为例,除了“两个 recipe 触发折扣”,还要测:
- 添加同一个 recipe 两次
- 删除不存在 recipe
- 删除后折扣降档
- undo add
- undo remove
- redo 后再新 add,redo 历史被清空
测试越清楚,面试官越容易相信你的代码能上线。
回答模板
遇到 LLD/OOD 编码题,可以按这个顺序:
1. 复述需求和 API 语义
2. 列核心对象和状态
3. 说明关键不变量
4. 先写正确版本
5. 跑样例和边界测试
6. 分析复杂度
7. 讨论 follow-up 优化
关键不变量是很多人忽略的。例如:
- cart_ 和 ingredient_count_ 必须始终一致。
- undo_stack 只记录成功改变状态的操作。
- alert 的 last_notified_at 只在真正通知后更新。
- resource inheritance 查询不能越过显式 deny。
讲出这些不变量,你的答案会更像工程实现,而不是刷题代码。
结尾
LLD/OOD 面试的难点不是题目有多新,而是它要求你同时写代码、建模、维护状态和解释取舍。准备时不要只背某一道题的解法,要练“拿到一个小系统后如何拆状态、定 API、补测试、做增量优化”。
如果你做算法题还可以,但遇到 OOD、LLD、multi-part coding 容易乱,可以做一次针对性 mock。重点不是给你标准答案,而是训练你在 45 到 60 分钟里把题目推进成一个可运行、可解释、可扩展的小系统。你可以在服务和价格页面查看编码面试和 LLD/OOD 辅导选项;如果已经有具体面试时间,也可以通过联系我们页面说明目标岗位、面试轮次和准备进度。