这篇复盘记录我在 Google SDE 岗位 R1 的两个轮次:一轮 Coding,一轮纯 BQ,各 45 分钟。除了题目本身,我也把 Onsite 当天的差旅报销、进出办公区的流程这些琐碎但实用的细节一起整理了下来。如果你正在准备 Google 的现场面试,希望这份笔记能帮你把节奏和心态都调到位。
面试概览
R1 一共两轮,节奏很标准:第一轮先聊人再写代码,第二轮全程 BQ。两位面试官背景不同,风格也明显不一样。
| 轮次 | 时长 | 形式 | 考点 |
|---|---|---|---|
| Round 1(Coding) | 45 分钟 | 自我介绍 + 简历项目聊天 + 现场写代码 | 项目深度、Coding 思路、区间划分建模 |
| Round 2(BQ) | 45 分钟 | 纯行为面试,项目与协作深挖 | STAR 结构、判断过程、团队协作 |
一个体感:Coding 轮的前半段聊项目并不是走过场,面试官会顺着你的回答追问「具体你做了什么」;BQ 轮更是全程围绕你的真实经历深挖,套模板的答案很容易被问穿。
Round 1:Coding 轮
第一轮的面试官是位母语中文的工程师,全程节奏比较放松。开场是自我介绍,接着围绕简历聊项目:为什么选择 Google、项目里最大的挑战是什么、你是怎么解决的。这一段建议提前把一两个项目的技术细节和你个人的贡献理清楚,因为面试官会追着细节问,而不是听你复述 JD。
聊完项目大概过了三分之一时间,进入 Coding。
题目:租车订单排班
给定一组租车订单,每个订单有订单号、取车时间和还车时间。要求把订单分配到若干辆车上,使得同一辆车上的订单在时间上互不重叠;并设计一个 Car 类,持有这辆车以及分配到它身上的订单列表。
这本质上是一道**区间划分(interval partitioning)**问题:目标是用尽量少的车覆盖所有订单。
思路
- 把所有订单按取车时间升序排序。
- 维护一个最小堆,堆里放每辆车「最早可用时间」(也就是该车当前最后一单的还车时间)。
- 依次处理每个订单:看堆顶那辆车——如果它的还车时间
<=当前订单的取车时间,说明这辆车已经空出来了,直接复用;否则所有车都还在被占用,只能新开一辆车。 - 分配完后更新这辆车的可用时间,把它重新压回堆里。
关键点在 dry run 时要主动说清楚边界:还车时间恰好等于下一单取车时间时算不算冲突? 这要跟面试官确认口径——通常认为「上一单还了才能取下一单」,即 <= 视为可复用。
Python 解法
import heapq
from typing import List
class Order:
"""一条租车订单:订单号、取车时间、还车时间。"""
def __init__(self, order_id: str, pickup: int, ret: int):
self.order_id = order_id
self.pickup = pickup
self.ret = ret
class Car:
"""一辆车,持有分配到它身上的订单列表。"""
def __init__(self, car_id: int):
self.car_id = car_id
self.orders: List[Order] = []
@property
def available_at(self) -> int:
"""该车最早可用时间:最后一单的还车时间,无单则视为负无穷。"""
return self.orders[-1].ret if self.orders else float("-inf")
def assign(self, order: Order) -> None:
self.orders.append(order)
def assign_orders(orders: List[Order]) -> List[Car]:
"""把订单分配到尽量少的车上,同一辆车订单时间不重叠。"""
# 边界情况:没有订单直接返回空
if not orders:
return []
# Step 1: 按取车时间升序排序
orders.sort(key=lambda o: o.pickup)
cars: List[Car] = []
# 最小堆元素为 (最早可用时间, 车在 cars 中的下标)
heap: List[tuple] = []
for order in orders:
# Step 2: 堆顶车已空出(还车时间 <= 当前取车时间)则复用
if heap and heap[0][0] <= order.pickup:
_, idx = heapq.heappop(heap)
car = cars[idx]
else:
# Step 3: 否则新开一辆车
car = Car(car_id=len(cars))
cars.append(car)
idx = car.car_id
# Step 4: 分配后更新可用时间并压回堆
car.assign(order)
heapq.heappush(heap, (order.ret, idx))
return cars
时间复杂度:O(n log n),排序与堆操作都是 log 级。 空间复杂度:O(n),堆与车辆列表最多存放 n 个元素。
Dry run 演示
用订单 [(A, 1, 4), (B, 2, 5), (C, 4, 6), (D, 7, 8)](格式为 订单号, 取车, 还车)走一遍:
| 步骤 | 当前订单 | 堆顶可用时间 | 决策 | 车辆状态 |
|---|---|---|---|---|
| 处理 A(1,4) | A | 堆空 | 新开 Car0 | Car0=[A] |
| 处理 B(2,5) | B | 4 > 2 | 新开 Car1 | Car0=[A], Car1=[B] |
| 处理 C(4,6) | C | 4 <= 4 | 复用 Car0 | Car0=[A,C], Car1=[B] |
| 处理 D(7,8) | D | 5 <= 7 | 复用 Car1 | Car0=[A,C], Car1=[B,D] |
最终两辆车即可覆盖:Car0 装 A、C,Car1 装 B、D。
主动补充要验证的边界:
- 空输入 → 返回空列表。
- 端点相接 例如上例 C 的取车时间
4恰好等于 A 的还车时间4,按<=判定为可复用(这一口径要先跟面试官确认)。 - 全部重叠 例如所有订单时间都叠在一起,则每单都得新开一辆车。
Follow-up:如果最多只有 K 辆车?
面试官接着问:如果车队规模有上限,最多只有 K 辆车怎么办?这题的重点不在代码,而在先澄清业务需求。我当时是这样拆的:
- 如果所有订单都必须被满足:那就在需要第 (K+1) 辆车时直接返回「分配失败」——因为没有可行方案。
- 如果允许拒单:先问清楚目标是什么。是想保留价值最高的订单(比如长租、高单价),还是想最大化完成的订单数量?两个目标对应完全不同的策略:
- 若要最大化订单数,可以在堆容量达到 K 后,用类似「活动选择」的贪心,优先保留还车时间早的订单来腾出车辆。
- 若要最大化总价值,就更接近带权区间调度,可能需要 DP 或按价值排序的贪心权衡。
实现上,可以把堆容量封顶在 K:当堆里已有 K 辆车且堆顶车仍未空出时,就触发上面的拒单 / 失败逻辑。这里我没有急着写完整代码,而是把权衡讲清楚,让面试官看到我在动手前会先对齐需求。
Round 2:BQ 轮
第二轮的面试官来自印度,全程纯 BQ,围绕简历项目和团队协作深挖。问题都很经典,但追问很细:
- 当队友一开始不认同你的方案时,你怎么说服 TA?
- 多个任务同时抢占资源时,你如何排优先级?
- 当一个计划外的新机会出现,你会不会暂停手头的工作去追它?你是怎么判断的?
我的体会是,BQ 轮拿分的关键不是「答案漂亮」,而是讲清楚判断过程:
- 用真实的 STAR 故事,不要编。面试官会顺着细节追问,编的故事第二层就露馅了。
- 重点讲你是怎么权衡的,而不只是结论。比如第三问,面试官真正想听的是:你当时面临哪些约束(时间、人手、现有承诺)、你用什么标准去衡量新机会的价值、最后你具体做了什么、结果如何。
- 描述清楚约束条件和你个人的动作。BQ 考的是判断力和协作方式,把「我们团队」换成「我具体做了 X」会更有说服力。
其他 R2 Onsite 相关信息 / logistics
除了题目,Onsite 当天有不少流程和报销的细节,提前知道能省很多心:
- 机酒安排:酒店和机票是通过 Graebel 这家差旅服务商安排的。如果你的 POC 没提到差旅、Graebel 也一直没联系你,很可能是系统把你误登记成了本地候选人——这时候要主动联系 POC 更正。
- 地面交通:凭票可报销,上限 60 美元。我提交的是电子钱包截图 + Uber 的 PDF 收据,这套组合是能通过的。
- 餐费:Graebel 的邮件里没明确说餐费可报,但我提交后也没被拒。稳妥起见,建议先跟 POC 确认再报。
- Coding 环境:现场用的是公司提供的电脑,不需要登录个人邮箱;面试官会给你一个 interview code,用它进入 Coding 环境即可。
- 草稿纸:主动问的话是允许用的。
- 进出流程:第一位面试官会把你带进去;第二轮面试官直接进房间接着面。结束后你不能独自留在办公区,必须由人陪同带出。
- 一个没用的小尝试:我试过用另一个 offer 的 deadline 去催 POC 加速流程,但从结果看并没有明显加快。
备考建议
Google 的 R1 这两轮,考的其实是两种不同的能力,准备时要分开打磨。
- Coding 轮:区间类、堆、贪心、图论是高频。像这道租车排班,能一眼看出「区间划分 + 最小堆」的建模才是关键。练题时不只练出答案,更要练把建模思路讲出来——先讲清楚你为什么这么建模,再动手写。
- BQ 轮:提前准备 3-4 个能覆盖「说服他人 / 优先级取舍 / 面对不确定性」的真实故事,每个都用 STAR 打磨到能讲清约束、动作和结果,并且经得起追问。
- Follow-up 心态:碰到「最多 K 辆车」这类开放追问,别急着写代码,先澄清业务目标。对齐需求本身就是加分项。
FAQ
Q1:Coding 轮前面聊项目重要吗?
很重要,不是走过场。面试官会顺着你的回答追问「具体你做了什么、怎么解决的」。提前把一两个项目的技术细节和个人贡献理清楚,比背 JD 有用得多。
Q2:租车订单排班为什么用最小堆,而不是每来一单遍历所有车?
遍历所有车找空车是 O(n²)。用最小堆维护每辆车的「最早可用时间」,只需看堆顶就能判断能否复用,整体 O(n log n),在数据量大时优势明显,也更好口头解释。
Q3:还车时间恰好等于下一单取车时间,算冲突吗?
取决于业务口径,要主动跟面试官确认。常见约定是「上一单还了才能取下一单」,即还车时间 <= 取车时间视为可复用,代码里用 <= 判断即涵盖这种端点相接的情况。
Q4:「最多 K 辆车」的 follow-up 该怎么答?
先澄清需求:如果所有订单必须满足,需要第 K+1 辆车时就返回失败;如果允许拒单,再问目标是保留高价值订单还是最大化订单数量,不同目标对应不同策略。把权衡讲清楚比直接写代码更重要。
Q5:BQ 轮怎么答才不容易被问穿?
用真实的 STAR 故事,重点讲判断过程而非结论:说清你面临的约束、你个人具体做了什么、最后结果如何。编的故事在第二层追问时很容易露馅。
正在准备 Google SDE 的 Coding 与 BQ 轮? 我们熟悉这类区间建模题的讲法和 BQ 深挖的节奏,能陪你把建模思路和 STAR 故事都打磨到经得起追问。
立即添加微信 Coding0201,获取一对一定制备考方案。
联系方式
- 微信:Coding0201
- Email:[email protected]
- Telegram:@OAVOProxy