Articles · Uber
Uber 面试准备:从 Coding 追问到系统设计与项目复盘
Uber 软件工程师面试准备:先核对地区、级别与邀请,再用车辆占用区间练习同刻事件、测试与规模追问,推演位置候选和权威派单状态、竞争绑定与迟到重试。项目复盘说明个人责任、取舍和量测口径,不把积分隐藏的面经细节当事实,也不承诺统一轮次、题数或通过线。附五个相关练习题与明确的跨公司练习边界。
准备 Uber 软件工程师面试,先确认自己申请的团队、级别与邀请范围,再把三种能力连起来:代码在需求变化后仍然正确,系统能解释实时数据与权威状态的边界,项目回答能说明你亲自做过的决策。只收集“别人遇到什么题”,无法证明这三件事。
Uber 官方招聘说明把技术环节描述为协作解决问题,可能围绕一个共享问题或实际情境展开。这支持练习清楚思考、实现与协作,不支持给所有 SWE 岗位套上固定轮次。本文的区间题、派单推演与项目追问均为原创练习,不是 Uber 的真实试题或生产架构。
先判断面经是否与你的申请可比
“Uber 面经”包含实习、校招、社招、不同国家以及非 SWE 角色。第一步不是按帖子给自己安排四轮模拟,而是核对职位编号、工作地点、团队职责、目标级别,以及招募方给出的环节名称。若邀请只写 technical interview,继续确认是算法实现、已有代码修改、机器编码还是设计讨论。
一份2026 年公开候选人帖子提到个人经历中的 OA、技术沟通和后续面试,但技术细节有积分隐藏内容,本文没有读取那些部分。本次研究没有获得足够的独立、同周期、同市场 SWE 报告来交叉验证统一流程,因此不列固定题数、计时或通过线。帖子的“难”或“简单”也不是你的难度预测。
把有用信息分成三层:官方说明能确认哪些能力;与你条件相近的个人报告提出哪些待验证问题;你自己的邀请最终要求什么。旧帖仍可提供练习方向,但不能替代当前语言、工具、录屏或 AI 使用规则。使用公开文档和练习平台,不等于正式面试允许外部辅助。
可以向招募方问:“这轮是否需要运行代码?设计讨论偏服务架构还是类与接口?我应该准备怎样的项目介绍?”这类问题确认任务,不索取题目。没有回复时,为最可能的任务建立最低可用准备,同时把未知项保留在记录中。
Coding 先把边界变成可执行契约
下面的原创练习采用出行语境:给定一批车辆占用区间,返回同时被占用的车辆峰值。它训练区间排序、相同时间的事件处理与复杂度解释;它不是调度最优路线,也不需要推断 Uber 实际如何分配车辆。
半开区间 [start, end) 表示起点计入、终点不计入。车辆在 end 时刻已经释放,因此 [1,3) 与 [3,5) 可以复用一辆车。这个约定决定同刻事件的处理顺序,不只是数学符号。
先确认输入是有限列表,每项是两个整数,且 start < end;时间单位一致,输入不一定已排序。空列表返回零;重复区间代表两次独立占用,不合并;这版返回数量,不返回每辆车的分配方案。若题目要求零时长记录有效,应先修改契约,而不是悄悄在代码里忽略它。
给面试官两个判别例子:[(1,3),(3,5)] 应为一辆,[(1,3),(2,5)] 应为两辆。再问同一时刻释放三辆、加入两辆时是否仍按半开规则处理。比起重复“我会考虑 edge cases”,这些例子更容易暴露双方理解差异。
实现峰值,再用反例解释不变量
对每个开始时间增加一次占用,对结束时间减少一次占用。排序事件时,同刻先处理结束,避免把刚释放的车辆算成仍被占用。下面的函数不改变原输入;元组长度正确是输入契约,整数类型与非空区间则显式检查。
def peak_vehicles(intervals):
events = []
for start, end in intervals:
if type(start) is not int or type(end) is not int:
raise ValueError("integer endpoints required")
if start >= end:
raise ValueError("non-empty half-open interval required")
events.append((start, 1))
events.append((end, -1))
events.sort() # -1 before +1 at the same timestamp
active = peak = 0
for _, delta in events:
active += delta
peak = max(peak, active)
return peak
不变量是:处理到某个时间的全部事件后,active 等于该时刻仍在占用的区间数量。在同刻结束事件处理期间,数量只会下降;新增事件处理完后才达到这一时刻的占用值,因此中间步骤不会产生虚假的更大峰值。
如果把开始排在结束前面,相邻区间就会返回二,构成最小反例。若错误地去重完全相同的区间,[(1,4),(1,4)] 又会低估需求。分别保留这两个测试:一个针对时间契约,一个针对记录身份,不能只跑一个“大随机数组”就认为都验证了。
n 个区间产生 2n 个事件,排序使时间复杂度为 O(n log n),额外空间为 O(n)。这包含事件副本,不能说成原地或常数空间。口头说明复杂度后,再用空输入、全部重叠、包含区间和乱序输入验证,而不是用复杂度代替正确性。
追问改变的究竟是输入、输出还是规模
如果追加“输出每辆车负责哪些区间”,原峰值函数不足够。需要按开始时间处理预约,并维护按释放时间排序的车队;释放时间不晚于下一起点的车辆可以复用。还要定义多个可用车辆时的选择顺序,才能得到可重复的分配结果。
如果输入变成实时流,离线事件排序的假设也变了。你需要说明事件能否迟到、窗口何时完成、结束事件是否会先于开始事件抵达,以及迟到数据是纠正历史答案还是只影响未来估计。不要仅把列表换成队列,就声称已解决无限流。
如果存在接送间隔,车辆在预约结束后并不立即可用。一个简单练习变体是加入固定周转时间 g,把释放时刻改为 end + g;但实际路程时间会随地理位置变化,已不再是统一区间峰值问题。此时应承认模型边界,重新澄清任务。
准备时让伙伴一次只改变一项条件。先说“原来保证什么、现在不再保证什么”,再改实现,最后重跑原来的相邻区间测试。若只修新测试而破坏旧行为,你得到的是一个新答案,不是可控地扩展了原解法。
还可以要求“现在取消一个预约,再查询峰值”。当前函数每次重建事件,适合有限批次,不适合高频动态更新。先确认查询次数、时间范围和更新时间分辨率,再比较重新排序与维护索引的成本。动态结构通常用额外内存与实现复杂度换取更新速度,不能仅因为用了树,就假定所有操作都更快。
另一个容易遗漏的变化是从数量到位置:两次预约时间不重叠,也可能因为上一程结束地点距离下一程起点太远而无法复用同一车辆。区间峰值在这种情况下只是资源需求的下界,不是可执行的派车方案。能主动说明这个差异,才能把 Coding 结果接到出行系统的业务约束,而不是把正确的小算法当成完整调度器。
系统设计:位置候选不等于可以派单
出行场景最值得练习的不是多画几个服务,而是区分“哪些司机可能合适”和“这次派单已经合法成立”。地理位置索引可以帮助生成附近候选;它不应该单独决定司机是否空闲、订单是否已取消、另一个调度器是否刚完成绑定。
这是原创设计模型:位置上报包含司机标识、采样时间与单调序号。索引丢弃旧序号覆盖新位置的更新,并对长期没有上报的司机设置新鲜度边界。设备时间未必可信,实际系统还需要考虑服务端接收时间与时钟偏差;不能只比较两个客户端时间戳。
派单路径则把司机可用状态、行程状态和绑定版本作为权威事实。在这个练习中,我们选择同一区域的事务边界,让一次绑定同时验证“司机仍可用、行程仍待分配、版本仍匹配”,并原子改变双方状态。只有更新司机或只有更新行程,都不能保证一对一绑定。
如果它们被拆到不同服务,就必须另谈协调、预占、补偿与取消竞态。分布式锁也不能让所有错误消失:租约可能过期,旧持有者可能恢复执行。需要让权威写入拒绝旧版本或旧授权,而不是相信“拿过锁”永远有效。
用一次竞争和一次迟到重试检查设计
假设工作者 A、B 都从位置索引读到司机 D 空闲。A 成功提交 D 与行程 X 的绑定,B 随后尝试把 D 绑定到 Y。正确结果不是让缓存最后写入者获胜,而是 B 的权威更新失败,并重新查询或寻找其他候选。索引暂时落后可以影响效率,但不应造成重复派单。
再加一个更难的情况:A 提交后没有收到回复,于是重试。幂等意味着同一次业务请求重复到达时,不再产生第二次业务效果;它不意味着网络只发送一次。AWS 的幂等 API 说明讨论了调用方请求标识、原子记录与状态变化,以及同标识不同参数的处理边界。它支持这个工程原则,不证明 Uber 使用同一实现。
给绑定请求保存调用方范围内的请求键与参数指纹;重试同键同参数返回原绑定结果,同键不同参数拒绝。记录请求结果与改变绑定状态应处在同一个可靠提交边界,否则进程可能在绑定成功后、保存去重记录前崩溃。
最后推演旧请求迟到:行程已经取消,较早的工作者才恢复发送“确认”。合法状态转换和版本检查应阻止取消后的旧命令重开行程。幂等结果保留多久、取消后重试返回原结果还是当前状态,都需要明确契约;不能用永久保存所有键回避容量与数据生命周期。
容量估计要指出第一个会坏的地方
假设练习中有十万在线司机,每五秒上传一次位置,平均是两万次上报每秒。它只是人为假设,不是 Uber 当前流量。真正要解释的是地理分布、突发重连与写入成本,而不是把两万 QPS 写在架构图角落。
城市热点可能集中在少数网格;区域分片能隔离部分负载,但单个活动场所仍可能成为热点。定位上报与派单确认也有不同代价:前者允许一定合并和新鲜度损失,后者不能随便丢弃。不要把所有请求混在一个平均吞吐数字里。
若系统过载,可优先降低位置刷新频率或缩减候选数量,同时保护权威状态路径。说明代价:司机位置更旧、匹配质量下降、等待时间可能上升;没有量测不能声称性能一定提高。Google SRE 的过载讨论强调请求成本与资源限制,适合帮助检查只用 QPS 衡量容量的不足。
提出你会量测的信号:位置更新年龄、候选搜索延迟、绑定冲突比例、数据库锁等待与重试放大。每个信号对应不同故障;平均 API 延迟健康,不代表某个区域的派单没有失败。这也为项目复盘中的“为什么监控没有报警”建立了具体追问。
项目复盘要说出你改变了哪一个判断
选择一个真实项目,准备从用户症状到技术决策的短叙述。先交代目标、约束和自己的责任,再讲如何排除一个合理但错误的假设。最后说明实施了什么、哪些工作由同事负责、用什么证据观察结果,以及下一次会如何修改。
例如,下面是虚构的回答结构,不可照抄成个人经历:“我们发现某一地区的等待时间变长。我负责按地区拆分指标和检查位置新鲜度,同事负责索引部署。原先怀疑数据库全局过载,但全局吞吐没有解释局部症状;切分后发现一个热点的更新积压。”真正作答时,换成你能合法披露且确实做过的事实。
“改善延迟”仍需要分母:是所有请求还是一个地区,平均还是 P95,观测多久,同期是否有流量变化?若只能证明预发布测试通过,就说预发布结果,不把它升级为线上用户改善。不能透露内部数字时,可以用相对变化或区间,但不要编精确值。
准备三个反事实追问:“如果当时有更多时间,会先做什么?”“什么证据会让你选择另一方案?”“如果同事不支持你的建议,你如何推动下一步?”它们检验决策质量和协作,不是让你把所有团队成果都归到自己名下。
把下一次练习变成一次可观察的改进
以下题目训练本文的具体边界。只有标为 Uber 的记录才属于 Uber 公司记录;其他公司的题目是跨公司能力练习,不是 Uber 出题预测。保留完整英文标题,方便对照原始题目与解答。
| 题目 | 本篇为什么选它 | 练完应留下什么 |
|---|---|---|
| Assign the Minimum Fleet to Rental Reservations | 把峰值数量延伸到车辆分配 | 同刻释放与复用的测试 |
| Design a Ride-Sharing System (Uber-style Core Platform) | Uber 记录,讨论出行平台的状态边界 | 一次竞争绑定的失败时间线 |
| Design Real-Time Driver Pay Aggregation | DoorDash 场景,练习实时聚合与重复事件 | 身份、窗口和迟到策略 |
| Project Deep Dive: Proving Technical Depth and Cross-Team Alignment | 说明个人责任与跨团队依赖 | 一项可辩护的决策及替代方案 |
| Finding the Root Cause of an Intermittent Failure When the Obvious Metrics Look Healthy | 练习平均指标掩盖局部故障 | 排除假设的证据顺序 |
下一次从 Uber Software Engineer 题库选一题,先独立实现,再让伙伴改变一个条件。结束后不要只写“做对了”:记下哪个契约先前没确认、哪个反例推翻了初稿,以及哪个项目回答仍缺证据。准备的目标是能继续推理,不是预测一个不可验证的题单。
资料来源与延伸阅读
- Uber:How we hire,官方招聘说明
- 1Point3Acres:2026 年个人 Uber 经历,本文仅使用公开可见部分
- AWS Builders’ Library:Making retries safe with idempotent APIs
- Google SRE:Handling Overload
资料核对:2026 年 10 月 6 日。练习模型与示例回答是本文原创,不构成公司流程、题目或录取承诺。