Goldman Sachs 的 SDE VO 不是那種「秒殺一道 Hard 就過」的面試。它的風格非常一致:從暴力解一步步最佳化到最優,全程要你講清楚每一步的時間/空間複雜度。面試官人不錯、會給提示,但你必須展現清晰的思路鏈條。
這篇把一位候選人的四輪 VO 完整復盤——每輪的真題、解法、空間最佳化點,以及口述結構。
四輪總覽
| 輪次 | 內容 | 考察重點 |
|---|---|---|
| Round 1 | Distinct Subsequences + 原地排序 | DP + 空間最佳化 + 演算法選型 |
| Round 2 | Maximal Square + 大檔案外部排序 | 2D DP + 海量資料處理 |
| Round 3 | Maze BFS(30min)+ Splitwise LLD(30min) | 最短路 + 物件導向設計 |
| Round 4 | 系統設計 + 設計模式(1h) | 架構 + 技術選型權衡 |
Round 1:Distinct Subsequences + 原地排序
第一題:Distinct Subsequences(經典 DP)
給字串 s 和 t,求 s 的子序列中等於 t 的個數。
先寫 2D DP,再被要求最佳化空間複雜度。
def numDistinct(s, t):
n, m = len(s), len(t)
# dp[j] = s 的前綴裡等於 t[:j] 的子序列數
dp = [0] * (m + 1)
dp[0] = 1
for i in range(1, n + 1):
# 從右往左滾動,避免覆蓋本輪還要用的 dp[j-1]
for j in range(m, 0, -1):
if s[i-1] == t[j-1]:
dp[j] += dp[j-1]
return dp[m]
空間最佳化關鍵:2D 壓成 1D 滾動陣列時,內層迴圈必須從右往左,否則 dp[j-1] 會被本輪提前更新污染。這是面試官最愛追問的點。
第二題:原地排序(不用額外空間)
面試官問 quicksort 還是 heapsort,候選人選了 quicksort。關鍵是從暴力解逐步最佳化到最優,並清楚講出時間/空間複雜度:quicksort 平均 O(n log n)、原地、最壞 O(n²)(用隨機 pivot 緩解)。
Round 2:Maximal Square + 大檔案外部排序
第一題:Maximal Square(2D DP)
在 0/1 矩陣裡找最大全 1 正方形的面積。
def maximalSquare(matrix):
if not matrix:
return 0
n, m = len(matrix), len(matrix[0])
# dp[i][j] = 以 (i,j) 為右下角的最大正方形邊長
prev = [0] * (m + 1)
best = 0
for i in range(1, n + 1):
cur = [0] * (m + 1)
for j in range(1, m + 1):
if matrix[i-1][j-1] == '1':
cur[j] = min(prev[j], cur[j-1], prev[j-1]) + 1
best = max(best, cur[j])
prev = cur
return best * best
轉移核心:dp[i][j] = min(上, 左, 左上) + 1。被追問空間最佳化時,用滾動陣列壓到 O(m)。
第二題:大檔案外部排序
2GB 檔案、250MB 記憶體,如何排序?
框架:external sort——
- 分塊讀入,每塊(約 200MB)在記憶體裡排序後寫回磁碟
- k-way merge:用最小堆管理每個 chunk 的當前元素,每次彈出最小的寫入輸出
import heapq
def k_way_merge(sorted_chunks):
# sorted_chunks: 多個已排序的迭代器
heap = []
iters = [iter(c) for c in sorted_chunks]
for idx, it in enumerate(iters):
v = next(it, None)
if v is not None:
heapq.heappush(heap, (v, idx))
out = []
while heap:
v, idx = heapq.heappop(heap)
out.append(v)
nv = next(iters[idx], None)
if nv is not None:
heapq.heappush(heap, (nv, idx))
return out
被問 merge 階段細節時,強調「用最小堆管理各 chunk 當前元素」就是標準答案。
Round 3:Maze BFS + Splitwise LLD
前 30 分鐘 DSA:Maze 2(BFS 求最短路 + 最佳化)
標準 grid BFS,注意 visited 標記 + 佇列。最佳化點:雙向 BFS 或 A*(如果給了啟發函數)。
後 30 分鐘 LLD:設計 Splitwise
LLD 真正考綜合能力。結構化方法:
- 需求澄清:支援誰欠誰多少、分帳方式(均分/按比例/按份額)、群組、結算
- 核心類別設計:
class User:
def __init__(self, uid, name):
self.uid, self.name = uid, name
class Expense:
def __init__(self, paid_by, amount, split_type, splits):
self.paid_by = paid_by # User
self.amount = amount
self.split_type = split_type # EQUAL / EXACT / PERCENT
self.splits = splits # {user: share}
class BalanceSheet:
def __init__(self):
# balances[a][b] = a 欠 b 多少
self.balances = defaultdict(lambda: defaultdict(float))
def add_expense(self, expense):
share = self._compute_shares(expense)
for user, owed in share.items():
if user != expense.paid_by:
self.balances[user][expense.paid_by] += owed
- 擴展討論:簡化債務(debt simplification)、並發結算、edge case(自己付自己)。
要點:先澄清需求 → 定義類別與介面 → 最後討論擴展性與邊界。時間緊,不要求寫完整程式,但思路要清晰。
Round 4:系統設計 + 設計模式(最難)
1 小時分兩部分,深入討論當前專案架構 + 設計模式 / OOP 原則的應用。
- 面試官讓畫當前專案架構圖,逐個追問技術選型理由
- 提到用訊息佇列解耦服務時,被追問訊息遺失、重複消費怎麼處理
- 訊息遺失:生產者 ack + 持久化 + 重試
- 重複消費:消費端冪等(唯一 ID 去重 / 冪等表)
- 設計模式:結合專案講 Strategy(分帳方式)、Factory(物件建立)、Observer(事件通知)的真實應用,而不是背定義
備考建議
- 逐步最佳化的敘事:每道題先暴力、再最佳化、每步報複雜度——這是 GS 的核心評分維度。
- 空間最佳化是高頻追問:DP 題準備好滾動陣列的「從右往左」細節。
- LLD 要結構化:需求 → 類別設計 → 介面 → 擴展性,固定四段式。
- 系統設計結合專案:訊息佇列的可靠性(遺失/重複)幾乎必問。
FAQ
Q1:GS SDE VO 幾輪? 通常 4 輪 superday,覆蓋 DSA、LLD、系統設計、專案深挖。
Q2:演算法題難度如何? 以 LeetCode Medium 為主,但極其看重逐步最佳化 + 複雜度分析,不是 AC 就行。
Q3:LLD 要寫完整程式嗎? 不要求。重點是類別設計、關係、介面,時間不夠時講清結構即可。
Q4:系統設計會考標準題(如設計 Twitter)嗎? 更常見的是深挖你履歷裡的專案,讓你解釋架構與技術選型,比標準題更難準備。
正在準備 Goldman Sachs SDE 面試?
如果你卡在「能 AC 但講不清最佳化路徑」「LLD 沒框架」「系統設計被追問就慌」,可以聊聊看完整的面試陪跑方案:四輪真題精講 + 限時 mock + 全程即時輔助 + 逐輪複盤。
聯絡方式
需要面試真題與客製化備戰計畫?立刻聯絡微信 Coding0201,獲取真題。
Email: [email protected] Telegram: @OAVOProxy