這篇複盤記錄我在 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